﻿<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory">第22章 集成与扩展</title>
<link rel="stylesheet" href="css/espertech.css" type="text/css">
	<meta xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" name="generator" content="DocBook XSL-NS Stylesheets V1.74.0">
		<meta xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<link rel="home" href="index.html" title="Esper参考文档">
				<link rel="up" href="index.html" title="Esper参考文档">
					<link rel="prev" href="dataflow.html" title="第21章 EPL参考：数据流">
						<link rel="next" href="examples.html" title="第23章 示例、教程与案例研究">
</head>

<body>
	<p xmlns:d="http://docbook.org/ns/docbook" id="title">
		<a href="./index.html" class="site_href"><strong>www.espertech.com</strong></a><a href="http://www.espertech.com/esper/esper-documentation/" class="doc_href"><strong>Documentation</strong></a>
	</p>
	<ul xmlns:d="http://docbook.org/ns/docbook" class="docnav">
		<li class="previous"><a accesskey="p" href="dataflow.html"><strong>Prev</strong></a></li>
		<li class="next"><a accesskey="n" href="examples.html"><strong>Next</strong></a></li>
	</ul>
	<div class="chapter" lang="en-US">
		<div class="titlepage">
			<div>
				<div>
					<h2 class="title"><a id="extension"></a>第22章 集成与扩展</h2>
				</div>
			</div>
		</div>
		<div class="toc">
			<dl>
				<dt><span class="sect1"><a href="extension.html#extension-overview">22.1. 概述</a></span></dt>
				<dt><span class="sect1"><a href="extension.html#custom-singlerow-function">22.2. 单行函数</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#custom-singlerow-inlined">22.2.1. 使用内联类提供单行函数</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-singlerow-library">22.2.2. 使用应用类提供单行函数</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-single-row-cache">22.2.3. 值缓存</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-single-filter-optimizable">22.2.4. 过滤器谓词表达式中的单行函数</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-single-eventsparam">22.2.5. 接收事件作为参数的单行函数</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-single-returningevents">22.2.6. 返回事件的单行函数</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-single-receivectx">22.2.7. 接收上下文对象</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-single-rethrowex">22.2.8. 异常处理</a></span></dt>
					</dl>
				</dd>
				<dt><span class="sect1"><a href="extension.html#extension-virtualdw">22.3. 虚拟数据窗口</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#extension-virtualdw-howto">22.3.1. 使用方法</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#extension-virtualdw-vdwforge">22.3.2. 实现锻造器</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#extension-virtualdw-vdwfactoryfactory">22.3.3. 实现工厂工厂</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#extension-virtualdw-vdwfactory">22.3.4. 实现工厂</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#extension-virtualdw-vdw">22.3.5. 实现虚拟数据窗口</a></span></dt>
					</dl>
				</dd>
				<dt><span class="sect1"><a href="extension.html#custom-views">22.4. 数据窗口视图与派生值视图</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#custom-views-viewforge">22.4.1. 实现视图锻造器</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-views-viewfactory">22.4.2. 实现视图工厂</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-views-view">22.4.3. 实现视图</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-views-contract">22.4.4. 视图契约</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-views-config">22.4.5. 配置视图命名空间和名称</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-views-datawin">22.4.6. 数据窗口视图要求</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-views-derivedvalue">22.4.7. 派生值视图要求</a></span></dt>
					</dl>
				</dd>
				<dt><span class="sect1"><a href="extension.html#custom-aggregation-function">22.5. 聚合函数</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#custom-aggregation-single">22.5.1. 单函数聚合开发</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-aggregation-multi">22.5.2. 多函数聚合开发</a></span></dt>
					</dl>
				</dd>
				<dt><span class="sect1"><a href="extension.html#custom-pattern-guard">22.6. 模式守卫</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-guard-forge-implementing">22.6.1. 实现守卫锻造器</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-guard-factory-implementing">22.6.2. 实现守卫工厂</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-guard-implementing">22.6.3. 实现守卫类</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-guard-config">22.6.4. 配置守卫命名空间和名称</a></span></dt>
					</dl>
				</dd>
				<dt><span class="sect1"><a href="extension.html#custom-pattern-observer">22.7. 模式观察者</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-observer-forge-implementing">22.7.1. 实现观察者锻造器</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-observer-factory-implementing">22.7.2. 实现观察者工厂</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-observer-implementing">22.7.3. 实现观察者类</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-pattern-observer-config">22.7.4. 配置观察者命名空间和名称</a></span></dt>
					</dl>
				</dd>
				<dt><span class="sect1"><a href="extension.html#custom-datetimemethod">22.8. 日期时间方法</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#custom-datetimemethod-stepone">22.8.1. 实现DateTimeMethodForgeFactory接口</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-datetimemethod-steptwo">22.8.2. 实现静态方法</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-datetimemethod-stepthree">22.8.3. 将日期时间方法扩展添加到编译器配置</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-datetimemethod-stepfour">22.8.4. 使用新的日期时间方法</a></span></dt>
					</dl>
				</dd>
				<dt><span class="sect1"><a href="extension.html#custom-enummethod">22.9. 枚举方法</a></span></dt>
				<dd>
					<dl>
						<dt><span class="sect2"><a href="extension.html#custom-enummethod-stepone">22.9.1. 实现EnumMethodForgeFactory接口</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-enummethod-steptwo">22.9.2. 实现EnumMethodState接口</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-enummethod-stepthree">22.9.3. 实现处理静态方法</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-enummethod-stepfour">22.9.4. 将枚举方法扩展添加到编译器配置</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-enummethod-stepfive">22.9.5. 使用新的枚举方法</a></span></dt>
						<dt><span class="sect2"><a href="extension.html#custom-enummethod-lambda">22.9.6. Lambda参数补充说明</a></span></dt>
					</dl>
				</dd>
			</dl>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="extension-overview"></a>22.1. Overview</h2>
					</div>
				</div>
			</div>
			<p>This chapter summarizes integration and describes in detail each of the extension APIs that allow integrating external data and/or extend runtime functionality.</p>
			<p>
				For information on calling external services via instance method invocation, for instance to integrate with dependency injection frameworks such as Spring or Guice, please see <a class="xref" href="epl_clauses.html#variable_eventtype" title="5.17.5. Class and Event-Type Variables">Section 5.17.5, “Class and Event-Type Variables”</a>.
			</p>
			<p>
				For information on input and output adapters that connect to an event transport and perform event transformation for incoming and outgoing on-the-wire event data, for use with streaming data, please see the EsperIO reference documentation. The data flow instances as described in <a class="xref" href="dataflow.html" title="Chapter 21. EPL Reference: Data Flow">Chapter 21, <i>EPL Reference: Data Flow</i></a> are an easy way to plug in operators that perform input and output. Data flows allow providing parameters and managing individual flows independent of runtime lifecycle. Also consider using the Plug-in Loader API for creating a new adapter that starts or stops as part of the CEP runtime initialization and
				destroy lifecycle, see <a class="xref" href="apiruntime.html#apiruntime-plugin" title="16.15. Plug-In Loader">Section 16.15, “Plug-In Loader”</a>.
			</p>
			<p>
				To join data that resides in a relational database and that is accessible via JDBC driver and SQL statement the runtime offers syntax for using SQL within EPL, see <a class="xref" href="epl_clauses.html#histdata_overview" title="5.13. Accessing Relational Data via SQL">Section 5.13, “Accessing Relational Data via SQL”</a>. A relational database input and output adapter for streaming input from and output to a relational database also exists (EsperIO).
			</p>
			<p>
				To join data that resides in a non-relational store the runtime offers a two means: First, the virtual data window, as described below, for transparently integrating the external store as a named window. The second mechanism is a special join syntax based on static method invocation; see <a class="xref" href="epl_clauses.html#joining_method" title="5.14. Accessing Non-Relational Data via Method, Script or UDF Invocation">Section 5.14, “Accessing Non-Relational Data via Method, Script or UDF Invocation”</a>.
			</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="tip">
				<h2>Tip</h2>
				<p>The best way to test that your extension code works correctly is to write unit tests against a statement that utilizes the extension code. Samples can be obtained from Esper regression test code base.</p>
			</div>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="note">
				<h2>Note</h2>
				<p>
					For all extension code and similar to listeners and subscribers, to send events into the runtime from extension code the <code class="literal">routeEvent</code> method should be used (and not <code class="literal">sendEvent</code>) to avoid the possibility of stack overflow due to event-callback looping and ensure correct processing of the current and routed event. Note that if outbound-threading is enabled, listeners and subscribers should use <code class="literal">sendEvent</code> and not <code class="literal">routeEvent</code>.
				</p>
			</div>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="note">
				<h2>Note</h2>
				<p>For all extension code it is not safe to deploy and undeploy within the extension code. For example, it is not safe to implement a data window that deploys compiled modules and that undeploys deployments.</p>
			</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="custom-singlerow-function"></a>22.2. Single-Row Function</h2>
					</div>
				</div>
			</div>
			<a id="d0e52828" class="indexterm"></a><a id="d0e52833" class="indexterm"></a>
			<p>Single-row functions return a single value. They are not expected to aggregate rows but instead should be stateless non-blocking functions. These functions can appear in any expressions and can be passed any number of parameters.</p>
			<p>You may not override a built-in function with a single-row function provided by you. The single-row function you register must have a different name then any of the built-in functions.</p>
			<p>The EPL compiler provides two ways to provide plug-in single-row functions:</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
				<ol>
					<li>
						<p>
							An inlined class that is part of the same EPL module or another EPL module, see next under <a class="xref" href="extension.html#custom-singlerow-inlined" title="22.2.1. Using an Inlined Class to Provide a Single-Row Function">Section 22.2.1, “Using an Inlined Class to Provide a Single-Row Function”</a> .
						</p>
					</li>
					<li>
						<p>
							An external class that your application provides as part of the application, see below under <a class="xref" href="extension.html#custom-singlerow-library" title="22.2.2. Using an Application Class to Provide a Single-Row Function">Section 22.2.2, “Using an Application Class to Provide a Single-Row Function”</a> .
						</p>
					</li>
				</ol>
			</div>
			<p>An example single-row function can also be found in the examples under the runtime configuration example.</p>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-singlerow-inlined"></a>22.2.1. Using an Inlined Class to Provide a Single-Row Function</h3>
						</div>
					</div>
				</div>
				<p>
					You may use an inline class that is part of the EPL modules to provide a single-row function. For more information on inline classes see <a class="xref" href="inlinedclass.html" title="Chapter 18. Inlined Classes">Chapter 18, <i>Inlined Classes</i></a>. Using an inline class does not require any compiler configuration.
				</p>
				<p>
					Specify the <code class="literal">ExtensionSingleRowFunction</code> annotation on the class level and the <code class="literal">name</code> (the EPL function name) and <code class="literal">methodName</code> (the name of the exposed method). This annotation instructs the compiler that the inlined class exposes a single-row function.
				</p>
				<p>
					This sample EPL includes an inlined class by name <code class="literal">MyUtilityClass</code> that provides a public static method by name <code class="literal">computePercent</code> to return a percentage value:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">inlined_class """
  @com.espertech.esper.common.client.hook.singlerowfunc.ExtensionSingleRowFunction(name="computePercent", methodName="computePercent")
  public class MyUtilityClass {
    public static double computePercent(double amount, double total) {
      return amount / total * 100;
    }
  }
""" 
select computePercent(itemQuantity,totalQuantity) from OrderEvent</pre>
				<p>
					Only one <code class="literal">ExtensionSingleRowFunction</code> annotation can be specified per class and the annotation is only for use with inlined classes. The method can be overloaded. Using an inline class does not require any compiler configuration.
				</p>
				<p>
					When using <code class="literal">create inlined_class</code> the runtime resolves dependencies on EPL objects at time of deployment (the same as for all EPL objects).
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-singlerow-library"></a>22.2.2. Using an Application Class to Provide a Single-Row Function</h3>
						</div>
					</div>
				</div>
				<p>Your application may provide a class that exposes a single-row function. In this case you must configure the class name, name of the function and function method name as part of compiler configuration. This is not necessary when using inlined classes as discussed before.</p>
				<div class="sect3" lang="en-US">
					<div class="titlepage">
						<div>
							<div>
								<h4 class="title"><a id="custom-singlerow-implementing"></a>22.2.2.1. Implementing a Single-Row Function</h4>
							</div>
						</div>
					</div>
					<p>Single-row function classes have no further requirement then provide a public static method.</p>
					<p>The following sample single-row function simply computes a percentage value based on two number values.</p>
					<p>
						This sample class provides a public static method by name <code class="literal">computePercent</code> to return a percentage value:
					</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyUtilityClass {
  public static double computePercent(double amount, double total) {
    return amount / total * 100;
  }
}</pre>
				</div>
				<div class="sect3" lang="en-US">
					<div class="titlepage">
						<div>
							<div>
								<h4 class="title"><a id="custom-single-row-config"></a>22.2.2.2. Configuring the Single-Row Function Name</h4>
							</div>
						</div>
					</div>
					<p>The class name of the class, the method name and the function name of the new single-row function must be added to the compiler configuration. The configuration shown below is XML however the same options are available through the configuration API:</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-singlerow-function name="percent" function-class="mycompany.MyUtilityClass" function-method="computePercent" /&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
					<p>Note that the function name and method name need not be the same.</p>
					<p>The new single-row function is now ready to use in a statement:</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select percent(fulfilled,total) from MyEvent</pre>
					<p>When selecting from a single stream, you may also pass wildcard to the single-row function and the function receives the underlying event:</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select percent(*) from MyEvent</pre>
					<p>If the single-row function returns an object that provides further functions, you may chain function calls.</p>
					<p>
						The following demonstrates a chained single-row function. The example assumes that a single-row function by name <code class="literal">calculator</code> returns an object that provides the <code class="literal">add</code> function which accepts two parameters:
					</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select calculator().add(5, amount) from MyEvent</pre>
				</div>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-single-row-cache"></a>22.2.3. Value Cache</h3>
						</div>
					</div>
				</div>
				<p>When a single-row function receives parameters that are all constant values or expressions that themselves receive only constant values, the runtime can pre-evaluate the result of the single-row function at time of statement. By default, the runtime does not pre-evaluate the single-row function unless you configure the value cache as enabled.</p>
				<p>
					If using inlined classes and the <code class="literal">ExtensionSingleRowFunction</code> annotation, to enable specify the value cache as follows (default is disabled):
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">ExtensionSingleRowFunction(..., valueCache=com.espertech.esper.common.client.configuration.compiler.ConfigurationCompilerPlugInSingleRowFunction.ValueCache.ENABLED)</pre>
				<p>If using application classes and the compiler configuration, the following configuration XML enables the value cache for the single-row function:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-singlerow-function name="getDate" 
      function-class="mycompany.DateUtil" function-method="parseDate"
      value-cache="enabled" /&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
				<p>When the single-row function receives constants as parameters, the runtime computes the result once and returns the cached result for each evaluation:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select getDate('2002-05-30T9:00:00.000') from MyEvent</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-single-filter-optimizable"></a>22.2.4. Single-Row Functions in Filter Predicate Expressions</h3>
						</div>
					</div>
				</div>
				<p>Your EPL may use plug-in single row functions among the predicate expressions as part of the filters in a stream or pattern.</p>
				<p>
					For example, the EPL below uses the function <code class="literal">computeHash</code> as part of a predicate expression:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from MyEvent(computeHash(field) = 100)</pre>
				<p>When you have many statements or many context partitions that refer to the same function, event type and parameters in a predicate expression, the compiler may optimize evaluation: The function gets evaluated only once per event.</p>
				<p>While the optimization is enabled by default for all plug-in single row functions, you can also disable the optimization for a specific single-row function. By disabling the optimization for a single-row function the runtime may use less memory to identify reusable function footprints but may cause the runtime to evaluate each function more frequently than necessary.</p>
				<p>
					If using inlined classes and the <code class="literal">ExtensionSingleRowFunction</code> annotation, specify the filter optimizable flag as follows (default is enabled):
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">ExtensionSingleRowFunction(..., filterOptimizable=com.espertech.esper.common.client.configuration.compiler.ConfigurationCompilerPlugInSingleRowFunction.FilterOptimizable.DISABLED)</pre>
				<p>If using application classes and the compiler configuration, the following configuration XML disables the filter optimization for a single-row function (by default it is enabled):</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-singlerow-function name="computeHash" 
      function-class="mycompany.HashUtil" function-method="computeHash"
      filter-optimizable="disabled" /&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-single-eventsparam"></a>22.2.5. Single-Row Functions Taking Events as Parameters</h3>
						</div>
					</div>
				</div>
				<p>
					EPL allows parameters to a single-row function to be events. In this case, declare the method parameter type to either take <code class="literal">EventBean</code>, <code class="literal">Collection&lt;EventBean&gt;</code> or the underlying class as a parameter.
				</p>
				<p>Sample method footprints are:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public static double doCompute(EventBean eventBean) {...}
public static boolean doCheck(MyEvent myEvent, String text) {...}
public static String doSearch(Collection&lt;EventBean&gt; events) {...}</pre>
				<p>
					To pass the event, specify the stream alias, or wildcard <code class="literal">(*)</code> or the tag name when used in a pattern.
				</p>
				<p>The EPL below shows example uses:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from MyEvent(doCompute(me) = 100) as me</pre>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from MyEvent where doCompute(*) = 100</pre>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from pattern[a=MyEvent -&gt; MyEvent(doCheck(a, 'sometext'))]</pre>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from MyEvent#time(1 min) having doCompute(last(*))]</pre>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from MyEvent#time(1 min) having doSearch(window(*))]</pre>
				<p>
					Declare the method parameter as <code class="literal">Collection&lt;EventBean&gt;</code> if the method expects an expression result that returns multiple events.
				</p>
				<p>
					Declare the method parameter as <code class="literal">EventBean</code> if the method expects an expression result that returns a single event.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-single-returningevents"></a>22.2.6. Single-Row Functions Returning Events</h3>
						</div>
					</div>
				</div>
				<p>
					A single-row function may return events. Please declare your single-row function method to return <code class="literal">Collection&lt;EventBean&gt;</code> or <code class="literal">EventBean[]</code> and configure the event type name.
				</p>
				<p>
					For example, assuming there is an <code class="literal">MyItem</code> event type such as created via <code class="literal">create schema MyItem(id string)</code>:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public static EventBean[] myItemProducer(String string, EPLMethodInvocationContext context) {
  String[] split = string.split(",");
  EventBean[] events = new EventBean[split.length];
  for (int i = 0; i &lt; split.length; i++) {
    events[i] = context.getEventBeanService().adapterForMap(Collections.singletonMap("id", split[i]), "MyItem");
  }
  return events;
}</pre>
				<p>
					The sample EPL queries items filtering those items that have a given value for the <code class="literal">id</code> field:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select myItemProducer(ordertext).where(v =&gt; v.id in ('id1', 'id3')) as c0 from Order</pre>
				<p>
					If using inlined classes and the <code class="literal">ExtensionSingleRowFunction</code> annotation, specify the event type name as follows:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">ExtensionSingleRowFunction(..., eventTypeName="MyItem")</pre>
				<p>
					If using application classes and the compiler configuration, this sample code register the <code class="literal">myItemProducer</code> function as a single-row function with an event type name:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">ConfigurationCompilerPlugInSingleRowFunction entry = new ConfigurationCompilerPlugInSingleRowFunction();
entry.setName("myItemProducer");
entry.setFunctionClassName(...);
entry.setFunctionMethodName(...);
entry.setEventTypeName("MyItem");
Configuration configuration = new Configuration();
configuration.getCompiler().addPlugInSingleRowFunction(entry);</pre>
				<p>
					If your single row function returns <code class="literal">EventBean[]</code> and is used with enumeration methods the configuration must provide an event type name.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-single-receivectx"></a>22.2.7. Receiving a Context Object</h3>
						</div>
					</div>
				</div>
				<p>
					The runtime can pass an object containing contextual information such as statement name, function name, runtime URI and context partition id to your method. The container for this information is <code class="literal">EPLMethodInvocationContext</code> in package <code class="literal">com.espertech.esper.common.client.hook.expr</code>. Please declare your method to take <code class="literal">EPLMethodInvocationContext</code> as the last parameter. The runtime then passes the information along.
				</p>
				<p>A sample method footprint and EPL are shown below:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public static double computeSomething(double number, EPLMethodInvocationContext context) {...}</pre>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select computeSomething(10) from MyEvent</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-single-rethrowex"></a>22.2.8. Exception Handling</h3>
						</div>
					</div>
				</div>
				<p>By default the runtime logs any exceptions thrown by the single row function and returns a null value. To have exceptions be re-thrown instead, which makes exceptions visible to any registered exception handler, please configure as discussed herein.</p>
				<p>
					If using inlined classes and the <code class="literal">ExtensionSingleRowFunction</code> annotation, you may set rethrow as follows:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">ExtensionSingleRowFunction(..., rethrowExceptions=true)</pre>
				<p>
					If using application classes and the compiler configuration, set the <code class="literal">rethrow-exceptions</code> flag in the XML configuration or the <code class="literal">rethrowExceptions</code> flag in the API when registering the single row function to have the runtime re-throw any exceptions that the single row function may throw.
				</p>
			</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="extension-virtualdw"></a>22.3. Virtual Data Window</h2>
					</div>
				</div>
			</div>
			<p>Use a virtual data window if you have a (large) external data store that you want to access as a named window. The access is transparent: There is no need to use special syntax or join syntax. All regular queries including subqueries, joins, on-merge, on-select, on-insert, on-delete, on-update and fire-and-forget are supported with virtual data windows.</p>
			<p>
				There is no need to keep any data or events in memory with virtual data windows. The only requirement for virtual data windows is that all data rows returned are <code class="literal">EventBean</code> instances.
			</p>
			<p>When implementing a virtual data window it is not necessary to send any events into the runtime or to use insert-into. The event content is simply assumed to exist and accessible to the runtime via the API implementation you provide.</p>
			<p>
				The distribution ships with a sample virtual data window in the examples folder under the name <code class="literal">virtualdw</code>. The code snippets below are extracts from the example.
			</p>
			<p>
				We use the term <span class="emphasis"><em>store</em></span> here to mean a source set of data that is managed by the virtual data window. We use the term <span class="emphasis"><em>store row</em></span> or just <span class="emphasis"><em>row</em></span> to mean a single data item provided by the store. We use the term <span class="emphasis"><em>lookup</em></span> to mean a read operation against the store returning zero, one or many rows.
			</p>
			<p>Virtual data windows allow high-performance low-latency lookup by exposing all relevant statement access path information. This makes it possible for the virtual data window to choose the desired access method into its store.</p>
			<p>The following steps are required to develop and use a virtual data window:</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
				<ol>
					<li>
						<p>
							Implement the interface <code class="literal">com.espertech.esper.common.client.hook.vdw.VirtualDataWindowForge</code>. This class is used by the compiler.
						</p>
					</li>
					<li>
						<p>
							Implement the interface <code class="literal">com.espertech.esper.common.client.hook.vdw.VirtualDataWindowFactoryFactory</code>. This class is referred to, by class name, by the compiler. It is used at runtime.
						</p>
					</li>
					<li>
						<p>
							Implement the interface <code class="literal">com.espertech.esper.common.client.hook.vdw.VirtualDataWindowFactory</code> (used at runtime only).
						</p>
					</li>
					<li>
						<p>
							Implement the interface <code class="literal">com.espertech.esper.common.client.hook.vdw.VirtualDataWindow</code> (used at runtime only).
						</p>
					</li>
					<li>
						<p>
							Implement the interface <code class="literal">com.espertech.esper.common.client.hook.vdw.VirtualDataWindowLookup</code> (used at runtime only).
						</p>
					</li>
					<li>
						<p>Register the factory class in the configuration.</p>
					</li>
				</ol>
			</div>
			<p>Once you have completed above steps, the virtual data window is ready to use in statements.</p>
			<p>From a threading perspective, virtual data window implementation classes must be thread-safe if objects are shared between multiple named windows. If no objects are shared between multiple different named windows, thereby each object is only used for the same named window and other named windows receive a separate instance, it is no necessary that the implementation classes are thread-safe.</p>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="extension-virtualdw-howto"></a>22.3.1. How to Use</h3>
						</div>
					</div>
				</div>
				<p>Your application must first register the virtual data window factory as part of configuration:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">Configuration config = new Configuration();
config.getCompiler().addPlugInVirtualDataWindow("sample", "samplevdw", 
    SampleVirtualDataWindowForge.class.getName());</pre>
				<p>Your application may then create a named window backed by a virtual data window.</p>
				<p>
					For example, assume that the <code class="literal">SampleEvent</code> event type is declared as follows:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">create schema SampleEvent as (key1 string, key2 string, value1 int, value2 double)</pre>
				<p>
					The next statement creates a named window <code class="literal">MySampleWindow</code> that provides <code class="literal">SampleEvent</code> events and is backed by a virtual data window:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">create window MySampleWindow.sample:samplevdw() as SampleEvent</pre>
				<p>You may then access the named window, same as any other named window, for example by subquery, join, on-action, fire-and-forget query or by consuming its insert and remove stream. While this example uses Map-type events, the example code is the same for POJO or other events.</p>
				<p>Your application may obtain a reference to the virtual data window from the runtime context.</p>
				<p>This code snippet looks up the virtual data window by the named window name:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">try {
  return (VirtualDataWindow) runtime.getContext().lookup("/virtualdw/MySampleWindow");
}
catch (NamingException e) {
  throw new RuntimeException("Failed to look up virtual data window, is it created yet?");
}</pre>
				<div class="sect3" lang="en-US">
					<div class="titlepage">
						<div>
							<div>
								<h4 class="title"><a id="extension-virtualdw-howto-access"></a>22.3.1.1. Query Access Path</h4>
							</div>
						</div>
					</div>
					<p>When your application registers a subquery, join or on-action query or executes a fire-and-forget query against a virtual data window the runtime interacts with the virtual data window. The interaction is a two-step process.</p>
					<p>At time of deployment (once), the runtime uses the information the compiler collected by analyzing the EPL where-clause, if present. It then creates a list of hash-index and binary tree (btree, i.e. sorted) index properties. It passes the property names that are queried as well as the operators (i.e. =, &gt;, range etc.) to the virtual data window. The virtual data window returns a lookup strategy object to the runtime.</p>
					<p>At time of statement execution (repeatedly as triggered), the runtime uses that lookup strategy object to execute a lookup. It passes to the lookup all actual key values (hash, btree including ranges) to make fast and efficient lookup achievable.</p>
					<p>To explain in detail, assume that your application creates a statement with a subquery as follows:</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select (select * from MySampleWindow where key1 = 'A1') from OtherEvent</pre>
					<p>
						At the time of compilation of the statement above the compiler analyzes the statement. It determines that the subquery queries a virtual data window. It determines from the where-clause that the lookup uses property <code class="literal">key1</code> and hash-equals semantics. The runtime then provides this information as part of <code class="literal">VirtualDataWindowLookupContext</code> passed to the <code class="literal">getLookup</code> method. Your application may inspect hash and btree properties and may determine the appropriate store access method to use.
					</p>
					<p>
						The hash and btree property lookup information is for informational purposes, to enable fast and performant queries that return the smallest number of rows possible. Your implementation classes may use some or none of the information provided and may also instead return some or perhaps even all rows, as is practical to your implementation. The <code class="literal">where</code>-clause still remains in effect and gets evaluated on all rows that are returned by the lookup strategy.
					</p>
					<p>
						Following the above example, the sub-query executes once when a <code class="literal">OtherEvent</code> event arrives. At time of execution the runtime delivers the string value <code class="literal">A1</code> to the <code class="literal">VirtualDataWindowLookup</code> lookup implementation provided by your application. The lookup object queries the store and returns store rows as <code class="literal">EventBean</code> instances.
					</p>
					<p>As a second example, consider an EPL join statement as follows:</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from MySampleWindow, MyTriggerEvent where key1 = trigger1 and key2 = trigger2</pre>
					<p>
						The compiler analyzes the statement and the runtime passes to the virtual data window the information that the lookup occurs on properties <code class="literal">key1</code> and <code class="literal">key2</code> under hash-equals semantics. When a <code class="literal">MyTriggerEvent</code> arrives, it passes the actual value of the <code class="literal">trigger1</code> and <code class="literal">trigger2</code> properties of the current MyTriggerEvent to the lookup.
					</p>
					<p>As a last example, consider a fire-and-forget query as follows:</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from MySampleWindow key1 = 'A2' and value1 between 0 and 1000</pre>
					<p>
						The compiler analyzes the statement and the runtime passes to the virtual data window the lookup information. The lookup occurs on property <code class="literal">key1</code> under hash-equals semantics and on property <code class="literal">value1</code> under btree-open-range semantics. When your application executes the fire-and-forget query the runtime passes <code class="literal">A2</code> and the range endpoints <code class="literal">0</code> and <code class="literal">1000</code> to the lookup.
					</p>
					<p>
						For more information, please consult the JavaDoc API documentation for class <code class="literal">VirtualDataWindow</code>, <code class="literal">VirtualDataWindowLookupContext</code> or <code class="literal">VirtualDataWindowLookupFieldDesc</code>.
					</p>
				</div>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="extension-virtualdw-vdwforge"></a>22.3.2. Implementing the Forge</h3>
						</div>
					</div>
				</div>
				<p>For each named window that refers to the virtual data window, the runtime instantiates one instance of the forge at compile-time.</p>
				<p>A virtual data window forge class is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Implement the <code class="literal">initialize</code> method that accepts a virtual data window forge context object as a parameter.
							</p>
						</li>
						<li>
							<p>
								Implement the <code class="literal">getFactoryMode</code> method that information how to initialize the factory-factory class (the class that acts as a factory for virtual data window factories).
							</p>
						</li>
						<li>
							<p>
								Implement the <code class="literal">getUniqueKeyPropertyNames</code> method that can return the set of property names that are unique keys, for the purpose of query planning.
							</p>
						</li>
					</ul>
				</div>
				<p>
					The compiler instantiates a <code class="literal">VirtualDataWindowForge</code> instance for each named window created by <code class="literal">create window</code>. The compiler invokes the <code class="literal">initialize</code> method once in respect to the named window being created passing a <code class="literal">VirtualDataWindowForgeContext</code> context object.
				</p>
				<p>
					The sample code shown here can be found among the examples in the distribution under <code class="literal">virtualdw</code>:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class SampleVirtualDataWindowForge implements VirtualDataWindowForge {

    public void initialize(VirtualDataWindowForgeContext initializeContext) {
    }

    public VirtualDataWindowFactoryMode getFactoryMode() {
        // The injection strategy defines how to obtain and configure the factory-factory.
        InjectionStrategy injectionStrategy = new InjectionStrategyClassNewInstance(SampleVirtualDataWindowFactoryFactory.class);
        
        // The managed-mode is the default. It uses the provided injection strategy.
        VirtualDataWindowFactoryModeManaged managed = new VirtualDataWindowFactoryModeManaged();
        managed.setInjectionStrategyFactoryFactory(injectionStrategy);
        
        return managed;
    }

    public Set&lt;String&gt; getUniqueKeyPropertyNames() {
        // lets assume there is no unique key property names
        return null;
    }
}</pre>
				<p>
					Your forge class must implement the <code class="literal">getFactoryMode</code> method which instructs the compiler how to obtain a factory class that returns a factory for creating virtual data window instances (a factory-factory). The class acting as the factory-factory will be <code class="literal">SampleVirtualDataWindowFactoryFactory</code>.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="extension-virtualdw-vdwfactoryfactory"></a>22.3.3. Implementing the Factory-Factory</h3>
						</div>
					</div>
				</div>
				<p>At deployment time, the runtime instantiates the factory-factory and obtains a factory for virtual data windows.</p>
				<p>A virtual data window factory-factory class is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Implement the <code class="literal">createFactory</code> method that accepts a factory-factory context and that returns the virtual data window factory.
							</p>
						</li>
					</ul>
				</div>
				<p>
					The sample code shown here can be found among the examples in the distribution under <code class="literal">virtualdw</code>:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class SampleVirtualDataWindowFactoryFactory implements VirtualDataWindowFactoryFactory {

    public VirtualDataWindowFactory createFactory(VirtualDataWindowFactoryFactoryContext ctx) {
        return new SampleVirtualDataWindowFactory();
    }
}
</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="extension-virtualdw-vdwfactory"></a>22.3.4. Implementing the Factory</h3>
						</div>
					</div>
				</div>
				<p>For each named window that refers to the virtual data window, the runtime instantiates one instance of the factory.</p>
				<p>A virtual data window factory class is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Implement the <code class="literal">initialize</code> method that accepts a virtual data window factory context object as a parameter.
							</p>
						</li>
						<li>
							<p>
								Implement the <code class="literal">create</code> method that accepts a virtual data window context object as a parameter and returns a <code class="literal">VirtualDataWindow</code> implementation.
							</p>
						</li>
						<li>
							<p>
								Implement the <code class="literal">destroy</code> method that gets called once when the named window is undeployed.
							</p>
						</li>
					</ul>
				</div>
				<p>
					The runtime instantiates a <code class="literal">VirtualDataWindowFactory</code> instance for each named window created via <code class="literal">create window</code>. The runtime invokes the <code class="literal">initialize</code> method once in respect to the named window being created passing a <code class="literal">VirtualDataWindowFactoryContext</code> context object.
				</p>
				<p>
					If not using contexts, the runtime calls the <code class="literal">create</code> method once after calling the <code class="literal">initialize</code> method. If using contexts, the runtime calls the <code class="literal">create</code> method every time it allocates a context partition. If using contexts and your virtual data window implementation operates thread-safe, you may return the same virtual data window implementation object for each context partition. If using contexts and your implementation object is not thread safe, return a separate thread-safe implementation object for each context partition.
				</p>
				<p>
					The runtime invokes the <code class="literal">destroy</code> method once when the named window is undeployed. If not using contexts, the runtime calls the <code class="literal">destroy</code> method of the virtual data window implementation object before calling the <code class="literal">destroy</code> method on the factory object. If using contexts, the runtime calls the <code class="literal">destroy</code> method on each instance associates to a context partition at the time the associated context partition terminates.
				</p>
				<p>
					The sample code shown here can be found among the examples in the distribution under <code class="literal">virtualdw</code>:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class SampleVirtualDataWindowFactory implements VirtualDataWindowFactory {

    public void initialize(VirtualDataWindowFactoryContext factoryContext) {
    }

    public VirtualDataWindow create(VirtualDataWindowContext context) {
        return new SampleVirtualDataWindow(context);
    }

    public void destroy() {
        // cleanup can be performed here
    }

    public Set&lt;String&gt; getUniqueKeyPropertyNames() {
        // lets assume there is no unique key property names
        return null;
    }
}</pre>
				<p>
					Your factory class must implement the <code class="literal">create</code> method which receives a <code class="literal">VirtualDataWindowContext</code> object. This method is called once for each EPL that creates a virtual data window (see example <code class="literal">create window</code> above).
				</p>
				<p>
					The <code class="literal">VirtualDataWindowContext</code> provides to your application:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">String namedWindowName;	// Name of named window being created.
Object[] parameters;  // Any optional parameters provided as part of create-window.
EventType eventType;  // The event type of events.
EventBeanFactory eventFactory;  // A factory for creating EventBean instances from store rows.
VirtualDataWindowOutStream outputStream;  // For stream output to consuming statements.
AgentInstanceContext agentInstanceContext;  // Other statement information in statement context.</pre>
				<p>When using contexts you can decide whether your factory returns a new virtual data window for each context partition or returns the same virtual data window instance for all context partitions. Your extension code may refer to the named window name to identify the named window and may refer to the agent instance context that holds the agent instance id which is the id of the context partition.</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="extension-virtualdw-vdw"></a>22.3.5. Implementing the Virtual Data Window</h3>
						</div>
					</div>
				</div>
				<p>A virtual data window implementation is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Accept the lookup context object as a parameter and return the <code class="literal">VirtualDataWindowLookup</code> implementation.
							</p>
						</li>
						<li>
							<p>Optionally, post insert and remove stream data.</p>
						</li>
						<li>
							<p>
								Implement the <code class="literal">destroy</code> method, which the runtime calls for each context partition when the named window is stopped or destroyed, or once when a context partition is ended/terminated.
							</p>
						</li>
					</ul>
				</div>
				<p>
					The sample code shown here can be found among the examples in the distribution under <code class="literal">virtualdw</code>.
				</p>
				<p>
					The implementation class must implement the <code class="literal">VirtualDataWindow</code> interface like so:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class SampleVirtualDataWindow implements VirtualDataWindow {

  private final VirtualDataWindowContext context;
  
  public SampleVirtualDataWindow(VirtualDataWindowContext context) {
    this.context = context;
  } ...</pre>
				<p>
					When the compiler compiles a statement and detects a virtual data window, the compiler compiles access path information and the runtime invokes the <code class="literal">getLookup</code> method indicating hash and btree access path information by passing a <code class="literal">VirtualDataWindowLookupContext</code> context. The lookup method must return a <code class="literal">VirtualDataWindowLookup</code> implementation that the statement uses for all lookups until the statement is stopped or destroyed.
				</p>
				<p>The sample implementation does not use the hash and btree access path information and simply returns a lookup object:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public VirtualDataWindowLookup getLookup(VirtualDataWindowLookupContext desc) {

  // Place any code that interrogates the hash-index and btree-index fields here.

  // Return the lookup strategy.
  return new SampleVirtualDataWindowLookup(context);
}</pre>
				<p>
					The runtime calls the <code class="literal">update</code> method when data changes because of on-merge, on-delete, on-update or insert-into. For example, if you have an on-merge statement that is triggered and that updates the virtual data window, the <code class="literal">newData</code> parameter receives the new (updated) event and the <code class="literal">oldData</code> parameter receives the event prior to the update. Your code may use these events to update the store or delete from the store, if needed.
				</p>
				<p>
					If your application plans to consume data from the virtual data window, for example via <code class="literal">select * from MySampleWindow</code>, then the code must implement the <code class="literal">update</code> method to forward insert and remove stream events, as shown below, to receive the events in consuming statements. To post insert and remove stream data, use the <code class="literal">VirtualDataWindowOutStream</code> provided by the context object as follows.
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void update(EventBean[] newData, EventBean[] oldData) {
  // This sample simply posts into the insert and remove stream what is received.
  context.getOutputStream().update(newData, oldData);
}</pre>
				<p>
					Your application should not use <code class="literal">VirtualDataWindowOutStream</code> to post new events that originate from the store. The object is intended for use with on-action statements. Use insert-into instead for any new events that originate from the store.
				</p>
			</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="custom-views"></a>22.4. Data Window View and Derived-Value View</h2>
					</div>
				</div>
			</div>
			<a id="d0e53573" class="indexterm"></a><a id="d0e53578" class="indexterm"></a>
			<p>Views in EPL are used to derive information from an event stream, and to represent data windows onto an event stream. This chapter describes how to plug-in a new, custom view.</p>
			<p>The following steps are required to develop and use a custom view.</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
				<ol>
					<li>
						<p>Implement a view forge class. View forges are compile-time classes that accept and check view parameters and refer to the appropriate view factory for the runtime.</p>
					</li>
					<li>
						<p>Implement a view factory class. View factories are classes that instantiate the appropriate view class at runtime.</p>
					</li>
					<li>
						<p>Implement a view class. A view class commonly represents a data window or derives new information from a stream at runtime.</p>
					</li>
					<li>
						<p>Configure the view factory class supplying a view namespace and name in the compiler configuration.</p>
					</li>
				</ol>
			</div>
			<p>
				The example view factory and view class that are used in this chapter can be found in the examples source folder in the OHLC (open-high-low-close) example. The class names are <code class="literal">OHLCBarPlugInViewForge</code>, <code class="literal">OHLCBarPlugInViewFactory</code> and <code class="literal">OHLCBarPlugInView</code>.
			</p>
			<p>
				Views can make use of the runtime services available via <code class="literal">StatementContext</code>, for example:
			</p>
			<div class="itemizedlist">
				<ul compact="compact">
					<li>
						<p>
							The <code class="literal">SchedulingService</code> interface allows views to schedule timer callbacks to a view
						</p>
					</li>
				</ul>
			</div>
			<p>
				<a class="xref" href="extension.html#custom-views-contract" title="22.4.4. View Contract">Section 22.4.4, “View Contract”</a> outlines the requirements for correct behavior of your custom view within the runtime.
			</p>
			<p>Note that custom views may use runtime services and APIs that can be subject to change between major releases. The runtime services discussed above and view APIs are considered part of the runtime internal API and are only limited stable. Please also consider contributing your custom view to the project by submitting the view code.</p>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-views-viewforge"></a>22.4.1. Implementing a View Forge</h3>
						</div>
					</div>
				</div>
				<p>A view forge class is a compile-time class and is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>Accept zero, one or more view parameters. View parameters are themselves expressions. The view forge must validate the expressions.</p>
						</li>
						<li>
							<p>Build the view factory class. At deployment-time this code executes and builds the view factory.</p>
						</li>
						<li>
							<p>Provide information about the event type of events posted by the view.</p>
						</li>
					</ul>
				</div>
				<p>
					View forge classes must implement the <code class="literal">ViewFactoryForge</code> interface. Additionally a view forge class must implement the <code class="literal">DataWindowViewForge</code> interface if the view is a data window (retains events provided to it).
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class OHLCBarPlugInViewForge implements ViewFactoryForge { ...</pre>
				<p>
					Your view forge class must implement the <code class="literal">setViewParameters</code> method to accept view parameters and the <code class="literal">attach</code> method to attach the view to a stream:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class OHLCBarPlugInViewForge implements ViewFactoryForge {
    private List&lt;ExprNode&gt; viewParameters;
    private ExprNode timestampExpression;
    private ExprNode valueExpression;
    private EventType eventType;

    public void setViewParameters(List&lt;ExprNode&gt; parameters, ViewForgeEnv viewForgeEnv, int streamNumber) throws ViewParameterException {
        this.viewParameters = parameters;
    }

    public void attach(EventType parentEventType, int streamNumber, ViewForgeEnv env, boolean grouped) throws ViewParameterException {
        if (viewParameters.size() != 2) {
            throw new ViewParameterException("View requires a two parameters: the expression returning timestamps and the expression supplying OHLC data points");
        }
        ExprNode[] validatedNodes = ViewForgeSupport.validate("OHLC view", parentEventType, viewParameters, false, env, streamNumber);

        timestampExpression = validatedNodes[0];
        valueExpression = validatedNodes[1];

        if (!JavaClassHelper.isTypeLong(timestampExpression.getForge().getEvaluationType())) {
            throw new ViewParameterException("View requires long-typed timestamp values in parameter 1");
        }
        if (!JavaClassHelper.isTypeDouble(valueExpression.getForge().getEvaluationType())) {
            throw new ViewParameterException("View requires double-typed values for in parameter 2");
        }
        ....</pre>
				<p>After the compiler supplied view parameters to the forge, the compiler will ask the view to attach to its parent and validate any parameter expressions against the parent view's event type. If the view will be generating events of a different type then the events generated by the parent view, then the view factory can allocate the new event type.</p>
				<p>Finally, the compiler asks the view forge to generate code that initializes the view factory:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public CodegenExpression make(CodegenMethodScope parent, SAIFFInitializeSymbol symbols, CodegenClassScope classScope) {
    return new SAIFFInitializeBuilder(new EPTypeClass(OHLCBarPlugInViewFactory.class), this.getClass(), "factory", parent, symbols, classScope)
                .exprnode("timestampExpression", timestampExpression)
                .exprnode("valueExpression", valueExpression)
                .build();
}</pre>
				<p>
					Use the internal <code class="literal">SAIFFInitializeBuilder</code> to build your view factory providing it the expressions and other values it needs.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-views-viewfactory"></a>22.4.2. Implementing a View Factory</h3>
						</div>
					</div>
				</div>
				<p>A view factory class is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>Implement initialization code when required.</p>
						</li>
						<li>
							<p>Instantiate the actual view class.</p>
						</li>
						<li>
							<p>Provide information about the event type of events posted by the view.</p>
						</li>
					</ul>
				</div>
				<p>
					View factory classes implement the <code class="literal">ViewFactory</code> interface. Additionally a view factory class must implement the <code class="literal">DataWindowViewFactory</code> interface if the view is a data window (retains events provided to it).
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class OHLCBarPlugInViewFactory implements ViewFactory { ...</pre>
				<p>
					The runtime initializes a view factory by calling its <code class="literal">init</code> method.
				</p>
				<p>The runtime asks the view factory to create a view instance, and asks for the type of event generated by the view:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public View makeView(AgentInstanceViewFactoryChainContext agentInstanceViewFactoryContext) {
    return new OHLCBarPlugInView(this, agentInstanceViewFactoryContext);
}

public EventType getEventType() {
    return eventType;
}</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-views-view"></a>22.4.3. Implementing a View</h3>
						</div>
					</div>
				</div>
				<p>A view class is responsible for:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								The <code class="literal">update</code> method receives insert streams and remove stream events from its parent view
							</p>
						</li>
						<li>
							<p>
								The <code class="literal">iterator</code> method supplies an (optional) iterator to allow an application to pull or request results from an <code class="literal">EPStatement</code>
							</p>
						</li>
					</ul>
				</div>
				<p>
					View classes subclass <code class="literal">ViewSupport</code>. Additionally a view class must implement the <code class="literal">DataWindowView</code> interface if the view is a data window (retains events provided to it).
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class OHLCBarPlugInView extends ViewSupport { ...</pre>
				<p>
					Your view's <code class="literal">update</code> method will be processing incoming (insert stream) and outgoing (remove stream) events posted by the parent view (if any), as well as providing incoming and outgoing events to child views. The convention required of your update method implementation is that the view releases any insert stream events (EventBean object references) which the view generates as reference-equal remove stream events (EventBean object references) at a later time.
				</p>
				<p>
					The view implementation must call <code class="literal">child.update(...)</code> to post outgoing insert and remove stream events. Similar to the <code class="literal">update</code> method, the <code class="literal">child.update</code> takes insert and remove stream events as parameters.
				</p>
				<p>
					A sample <code class="literal">update</code> method implementation is provided in the OHLC example.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-views-contract"></a>22.4.4. View Contract</h3>
						</div>
					</div>
				</div>
				<p>
					The <code class="literal">update</code> method must adhere to the following conventions, to prevent memory leaks and to enable correct behavior within the runtime:
				</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								A view implementation that posts events to the insert stream must post unique <code class="literal">EventBean</code> object references as insert stream events, and cannot post the same <code class="literal">EventBean</code> object reference multiple times. The underlying event to the <code class="literal">EventBean</code> object reference can be the same object reference, however the <code class="literal">EventBean</code> object reference posted by the view into the insert stream must be a new instance for each insert stream event.
							</p>
						</li>
						<li>
							<p>
								If the custom view posts a continuous insert stream, then the views must also post a continuous remove stream (second parameter to the <code class="literal">updateChildren</code> method). If the view does not post remove stream events, it assumes unbound keep-all semantics.
							</p>
						</li>
						<li>
							<p>
								<code class="literal">EventBean</code> events posted as remove stream events must be the same object reference as the <code class="literal">EventBean</code> events posted as insert stream by the view. Thus remove stream events posted by the view (the <code class="literal">EventBean</code> instances, does not affect the underlying representation) must be reference-equal to insert stream events posted by the view as part of an earlier invocation of the update method, or the same invocation of the update method.
							</p>
						</li>
						<li>
							<p>
								<code class="literal">EventBean</code> events represent a unique observation. The values of the observation can be the same, thus the underlying representation of an <code class="literal">EventBean</code> event can be reused, however event property values must be kept immutable and not be subject to change.
							</p>
						</li>
						<li>
							<p>
								Array elements of the insert and remove stream events must not carry null values. Array size must match the number of <code class="literal">EventBean</code> instances posted. It is recommended to use a <code class="literal">null</code> value for no insert or remove stream events rather then an empty zero-size array.
							</p>
						</li>
					</ul>
				</div>
				<p>
					Your view implementation must implement the <code class="literal">AgentInstanceStopCallback</code> interface to receive a callback when the view gets destroyed.
				</p>
				<p>
					Please refer to the sample views for a code sample on how to implement the <code class="literal">iterator</code> method.
				</p>
				<p>In terms of multiple threads accessing view state, there is no need for your custom view factory or view implementation to perform any synchronization to protect internal state. The iterator of the custom view implementation does also not need to be thread-safe. The runtime ensures the custom view executes in the context of a single thread at a time. If your view uses shared external state, such external state must be still considered for synchronization when using multiple threads.</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-views-config"></a>22.4.5. Configuring View Namespace and Name</h3>
						</div>
					</div>
				</div>
				<p>The view factory class name as well as the view namespace and name for the new view must be added to the compiler configuration. The configuration shown below is XML however the same options are available through configuration:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-view namespace="custom" name="ohlc" 
        forge-class="com.espertech.esper.example.ohlc.OHLCBarPlugInViewFactory" /&gt; 
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
				<p>The new view is now ready to use in a statement:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from StockTick.custom:ohlc(timestamp, price)</pre>
				<p>Note that the view must implement additional interfaces if it acts as a data window view, or works in a grouping context, as discussed in detail below.</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-views-datawin"></a>22.4.6. Requirement for Data Window Views</h3>
						</div>
					</div>
				</div>
				<p>Your custom view may represent an expiry policy and may retain events and thus act as a data window view. In order to allow the compiler to validate that your view can be used with named windows, which allow only data window views, this section documents any additional requirement that your classes must fulfill.</p>
				<p>
					Your view forge class must implement the <code class="literal">DataWindowViewForge</code> interface. This marker interface (no methods required) indicates that your views are data window views.
				</p>
				<p>
					Your view factory class must implement the <code class="literal">DataWindowViewFactory</code> interface. This marker interface (no methods required) indicates that your views are data window views.
				</p>
				<p>
					Your view class must implement the <code class="literal">DataWindowView</code> interface. This interface indicates that your view is a data window view and therefore eligible to be used in any construct that requires a data window view. The <code class="literal">DataWindowView</code> interface extends the <code class="literal">ViewDataVisitable</code> interface. Please provide an empty implementation method for the <code class="literal">visitView</code> method as required by <code class="literal">ViewDataVisitable</code> (the default behavior is sufficient).
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-views-derivedvalue"></a>22.4.7. Requirement for Derived-Value Views</h3>
						</div>
					</div>
				</div>
				<p>Your custom view may compute derived information from the arriving stream, instead of retaining events, and thus act as a derived-value view.</p>
				<p>
					Your view class should implement the <code class="literal">DerivedValueView</code> interface. This marker interface indicates that your view is a derived-value view, affecting correct behavior of the view when used in joins.
				</p>
			</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="custom-aggregation-function"></a>22.5. Aggregation Function</h2>
					</div>
				</div>
			</div>
			<a id="d0e53891" class="indexterm"></a><a id="d0e53896" class="indexterm"></a>
			<p>
				Aggregation functions are stateful functions that aggregate events, event property values or expression results. Examples for built-in aggregation functions are <code class="literal">count(*)</code>, <code class="literal">sum(price * volume)</code>, <code class="literal">window(*)</code> or <code class="literal">maxby(volume)</code>.
			</p>
			<p>
				EPL allows two different ways for your application to provide aggregation functions. We use the name <span class="emphasis"><em>aggregation single-function</em></span> and <span class="emphasis"><em>aggregation multi-function</em></span> for the two independent extension APIs for aggregation functions.
			</p>
			<p>The aggregation single-function API is simple to use however it imposes certain restrictions on how expressions that contain aggregation functions share state and how they are evaluated.</p>
			<p>The aggregation multi-function API is more powerful and provides control over how expressions that contain aggregation functions share state and are evaluated.</p>
			<p>The next table compares the two aggregation function extension API's:</p>
			<div class="table">
				<a id="d0e53929"></a>
				<p class="title">
					<b>Table 22.1. Aggregation Function Extension API's</b>
				</p>
				<div class="table-contents">
					<table summary="Aggregation Function Extension API's" border="1">
						<colgroup>
							<col>
								<col>
									<col>
						</colgroup>
						<thead>
							<tr>
								<th> </th>
								<th>Single-Function</th>
								<th>Multi-Function</th>
							</tr>
						</thead>
						<tbody>
							<tr>
								<td>Return Value</td>
								<td>Can only return a single value or object. Cannot return an <code class="literal">EventBean</code> event, collection of <code class="literal">EventBean</code> events or collection or array of values for use with enumeration methods, for example.
								</td>
								<td>Can return an <code class="literal">EventBean</code> event, a collection of <code class="literal">EventBean</code> events or a collection or array of objects for use with enumeration methods or to access event properties.
								</td>
							</tr>
							<tr>
								<td>Complexity of API</td>
								<td>Simple (consists of 2 interfaces).</td>
								<td>More complex (consists of 6 interfaces).</td>
							</tr>
							<tr>
								<td>State Sharing</td>
								<td>State and parameter evaluation shared if multiple aggregation functions of the same name in the same statement (and context partition) take the exact same parameter expressions.</td>
								<td>State and parameter evaluation sharable when multiple aggregation functions of a related name (related thru configuration) for the same statement (and context partition) exist, according to a sharing-key provided by your API implementation.</td>
							</tr>
							<tr>
								<td>Function Name</td>
								<td>Each aggregation function expression receives its own factory object.</td>
								<td>Multiple related aggregation function expressions share a single factory object.</td>
							</tr>
							<tr>
								<td>Distinct Keyword</td>
								<td>Handled by the runtime transparently depending on mode.</td>
								<td>Indicated to the API implementation only.</td>
							</tr>
						</tbody>
					</table>
				</div>
			</div>
			<br class="table-break">
				<p>The following sections discuss developing an aggregation single-function first, followed by the subject of developing an aggregation multi-function.</p>
				<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="note">
					<h2>Note</h2>
					<p>
						The aggregation multi-function API is a powerful and lower-level API to extend the runtime. Any classes that are not part of the <code class="literal">client</code> package should be considered unstable and are subject to change between minor and major releases.
					</p>
				</div>
				<div class="sect2" lang="en-US">
					<div class="titlepage">
						<div>
							<div>
								<h3 class="title"><a id="custom-aggregation-single"></a>22.5.1. Aggregation Single-Function Development</h3>
							</div>
						</div>
					</div>
					<p>
						This section describes the <span class="emphasis"><em>aggregation single-function</em></span> extension API for providing aggregation functions.
					</p>
					<p>The EPL compiler provides two ways to provide aggregation single-functions:</p>
					<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
						<ol>
							<li>
								<p>
									An inlined class that is part of the same EPL module or another EPL module, see next under <a class="xref" href="extension.html#custom-aggregation-inlined" title="22.5.1.4. Using an Inlined Class to Provide an Aggregation Single-Function">Section 22.5.1.4, “Using an Inlined Class to Provide an Aggregation Single-Function”</a> .
								</p>
							</li>
							<li>
								<p>
									An external class that your application provides as part of the application, see below under <a class="xref" href="extension.html#custom-aggregation-library" title="22.5.1.5. Using an Application Class to Provide the Aggregation Single-Function">Section 22.5.1.5, “Using an Application Class to Provide the Aggregation Single-Function”</a> .
								</p>
							</li>
						</ol>
					</div>
					<p>In either case, the following steps are required to develop and use a custom aggregation single-function.</p>
					<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
						<ol>
							<li>
								<p>
									Implement an aggregation function forge by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggfunc.AggregationFunctionForge</code>. This class provides compile-time information.
								</p>
							</li>
							<li>
								<p>
									Implement an aggregation function factory by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggfunc.AggregationFunctionFactory</code> (used at runtime).
								</p>
							</li>
							<li>
								<p>
									Implement an aggregation function by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggfunc.AggregationFunction</code> (used at runtime).
								</p>
							</li>
						</ol>
					</div>
					<p>
						Custom aggregation functions can also be passed multiple parameters, as further described in <a class="xref" href="extension.html#custom-aggregation-single-multiparam" title="22.5.1.6. Aggregation Single-Function: Accepting Multiple Parameters">Section 22.5.1.6, “Aggregation Single-Function: Accepting Multiple Parameters”</a>. In the example below the aggregation function accepts a single parameter.
					</p>
					<p>
						The code for the example aggregation function as shown in this chapter can be found in the runtime configuration example in the package <code class="literal">com.espertech.esper.example.runtimeconfig</code> by the name <code class="literal">MyConcatAggregationFunction</code>. The sample function simply concatenates string-type values.
					</p>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-single-forge"></a>22.5.1.1. Implementing an Aggregation Single-Function Forge</h4>
								</div>
							</div>
						</div>
						<p>An aggregation function forge class is only used at compile-time and is responsible for the following functions:</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement a <code class="literal">setFunctionName</code> method that receives the function name (optional, the default implementation is empty).
									</p>
								</li>
								<li>
									<p>
										Implement a <code class="literal">validate</code> method that validates the value type of the data points that the function must process.
									</p>
								</li>
								<li>
									<p>
										Implement a <code class="literal">getValueType</code> method that returns the type of the aggregation value generated by the aggregation function instances. For example, the built-in <code class="literal">count</code> aggregation function returns <code class="literal">Long.class</code> as it generates <code class="literal">long</code> -typed values.
									</p>
								</li>
								<li>
									<p>
										Implement a <code class="literal">getAggregationFunctionMode</code> which provided information about the factory class to the compiler.
									</p>
								</li>
							</ul>
						</div>
						<p>
							Aggregation forge classes implement the interface <code class="literal">AggregationFunctionForge</code>:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyConcatAggregationFunctionForge implements AggregationFunctionForge { ...</pre>
						<p>The compiler constructs one instance of the aggregation function forge class for each time the function is listed in a statement, however the compiler may decide to reduce the number of aggregation forge instances if it finds equivalent aggregations.</p>
						<p>
							The aggregation function forge instance receives the aggregation function name via set <code class="literal">setFunctionName</code> method.
						</p>
						<p>
							The sample concatenation function forge provides an empty <code class="literal">setFunctionName</code> method:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void setFunctionName(String functionName) {
  // no action taken
}</pre>
						<p>
							An aggregation function forge must provide an implementation of the <code class="literal">validate</code> method that is passed a <code class="literal">AggregationFunctionValidationContext</code> validation context object. Within the validation context you find the result type of each of the parameters expressions to the aggregation function as well as information about constant values and data window use. Please see the JavaDoc API documentation for a comprehensive list of validation context information.
						</p>
						<p>Since the example concatenation function requires string types it implements a type check:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void validate(AggregationValidationContext validationContext) {
  if (validationContext.getParameterTypes().length != 1 || !JavaClassHelper.isTypeString(validationContext.getParameterTypes()[0])) {
    throw new IllegalArgumentException("Concat aggregation requires a single parameter of type String");
  }
}</pre>
						<p>
							In order for the compiler to validate the type returned by the aggregation function against the types expected by enclosing expressions, the <code class="literal">getValueType</code> must return the result type of any values produced by the aggregation function:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public EPTypeClass getValueType() {
  return EPTypePremade.STRING.getEPType();
}</pre>
						<p>
							Finally the forge implementation must provide a <code class="literal">getAggregationFunctionMode</code> method that returns information about the factory. The compiler uses this information to build the aggregation function factory.
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public AggregationFunctionMode getAggregationFunctionMode() {
    // Inject a factory by using "new"
    InjectionStrategy injectionStrategy = new InjectionStrategyClassNewInstance(MyConcatAggregationFunctionFactory.class);
    
    // The managed mode means there is no need to write code that generates code
    AggregationFunctionModeManaged mode = new AggregationFunctionModeManaged();
    mode.setInjectionStrategyAggregationFunctionFactory(injectionStrategy);
        
    return mode;
}</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-single-factory"></a>22.5.1.2. Implementing an Aggregation Single-Function Factory</h4>
								</div>
							</div>
						</div>
						<p>An aggregation function factory class is responsible for the following functions:</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement a <code class="literal">newAggregator</code> method that instantiates and returns an aggregation function instance.
									</p>
								</li>
							</ul>
						</div>
						<p>
							Aggregation function factory classes implement the interface <code class="literal">AggregationFunctionFactory</code>:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyConcatAggregationFunctionFactory implements AggregationFunctionFactory { ...</pre>
						<p>The runtime constructs the aggregation function factory at time of deployment.</p>
						<p>
							The factory must provide a <code class="literal">newAggregator</code> method that returns instances of <code class="literal">AggregationFunction</code>. The runtime invokes this method for each new aggregation state to be allocated.
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public AggregationFunction newAggregator() {
  return new MyConcatAggregationFunction();
}</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-single-implementing"></a>22.5.1.3. Implementing an Aggregation Single-Function</h4>
								</div>
							</div>
						</div>
						<p>An aggregation function class is responsible for the following functions:</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement an <code class="literal">enter</code> method that the runtime invokes to add a data point into the aggregation, when an event enters a data window
									</p>
								</li>
								<li>
									<p>
										Implement a <code class="literal">leave</code> method that the runtime invokes to remove a data point from the aggregation, when an event leaves a data window
									</p>
								</li>
								<li>
									<p>
										Implement a <code class="literal">getValue</code> method that returns the current value of the aggregation.
									</p>
								</li>
								<li>
									<p>
										Implement a <code class="literal">clear</code> method that resets the current value.
									</p>
								</li>
							</ul>
						</div>
						<p>
							Aggregation function classes implement the interface <code class="literal">AggregationFunction</code>:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyConcatAggregationFunction implements AggregationFunction { ...</pre>
						<p>
							The class that provides the aggregation and implements <code class="literal">AggregationFunction</code> does not have to be threadsafe.
						</p>
						<p>The constructor initializes the aggregation function:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyConcatAggregationFunction implements AggregationFunction {
  private final static char DELIMITER = ' ';
  private StringBuilder builder;
  private String delimiter;

  public MyConcatAggregationFunction() {
    builder = new StringBuilder();
    delimiter = "";
  }
  ...</pre>
						<p>
							The <code class="literal">enter</code> method adds a datapoint to the current aggregation value. The example <code class="literal">enter</code> method shown below adds a delimiter and the string value to a string buffer:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void enter(Object value) {
  if (value != null) {
    builder.append(delimiter);
    builder.append(value.toString());
    delimiter = String.valueOf(DELIMITER);
  }
}</pre>
						<p>
							Conversly, the <code class="literal">leave</code> method removes a datapoint from the current aggregation value. The example <code class="literal">leave</code> method removes from the string buffer:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void leave(Object value) {
  if (value != null) {
    builder.delete(0, value.toString().length() + 1);
  }
}</pre>
						<p>
							Finally, the runtime obtains the current aggregation value by means of the <code class="literal">getValue</code> method:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public Object getValue() {
  return builder.toString();
}</pre>
						<p>
							For on-demand queries the aggregation function must support resetting its value to empty or start values. Implement the <code class="literal">clear</code> function to reset the value as shown below:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void clear() {
  builder = new StringBuilder();
  delimiter = "";
}</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-inlined"></a>22.5.1.4. Using an Inlined Class to Provide an Aggregation Single-Function</h4>
								</div>
							</div>
						</div>
						<p>
							You may use an inline class that is part of the EPL modules to provide an aggregation function. For more information on inline classes see <a class="xref" href="inlinedclass.html" title="Chapter 18. Inlined Classes">Chapter 18, <i>Inlined Classes</i></a>. Using an inline class does not require any compiler configuration.
						</p>
						<p>
							Specify the <code class="literal">ExtensionAggregationFunction</code> annotation on the class level of the <code class="literal">AggregationFunctionForge</code> implementation class and the <code class="literal">name</code> (the EPL aggregation function name). This annotation instructs the compiler that the inlined class exposes an aggregation function.
						</p>
						<p>
							This sample EPL includes an inlined class by name <code class="literal">ConcatAggForge</code> that provides a <code class="literal">concat</code> aggregation function that concatenates:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">inlined_class """
import com.espertech.esper.common.client.hook.aggfunc.*;
import com.espertech.esper.common.client.hook.forgeinject.*;
import com.espertech.esper.common.client.serde.*;
import java.io.*;
import com.espertech.esper.common.internal.epl.expression.core.*;
@ExtensionAggregationFunction(name="concat")
public class ConcatAggForge implements AggregationFunctionForge {
  public void validate(AggregationFunctionValidationContext validationContext) throws ExprValidationException {
    EPType paramType = validationContext.getParameterTypes()[0];
    if (paramType == EPTypeNull.INSTANCE || ((EPTypeClass) paramType).getType() != String.class) {
      throw new ExprValidationException("Invalid parameter type '" + paramType + "'");
    }
  }

  public EPTypeClass getValueType() {
    return new EPTypeClass(String.class);
  }

  public AggregationFunctionMode getAggregationFunctionMode() {
    AggregationFunctionModeManaged mode = new AggregationFunctionModeManaged();
    mode.setHasHA(true);
    mode.setSerde(ConcatAggSerde.class);
    mode.setInjectionStrategyAggregationFunctionFactory(new InjectionStrategyClassNewInstance(ConcatAggFactory.class.getName()));
    return mode;
  }

  public static class ConcatAggFactory implements AggregationFunctionFactory {
    public AggregationFunction newAggregator(AggregationFunctionFactoryContext ctx) {
      return new ConcatAggFunction();
    }
  }

  public static class ConcatAggFunction implements AggregationFunction {
    private final static String DELIMITER = ",";
    private StringBuilder builder;
    private String delimiter;

    public ConcatAggFunction() {
      super();
      builder = new StringBuilder();
      delimiter = "";
    }

    public void enter(Object value) {
      if (value != null) {
        builder.append(delimiter);
        builder.append(value.toString());
        delimiter = DELIMITER;
      }
    }

    public void leave(Object value) {
      if (value != null) {
        builder.delete(0, value.toString().length() + 1);
      }
    }
  
    public String getValue() {
      return builder.toString();
    }
  
    public void clear() {
      builder = new StringBuilder();
      delimiter = "";
    }
  }
  
  // the serializer-deserializer is only for high availability and is not required otherwise
  public static class ConcatAggSerde {
    public static void write(DataOutput output, AggregationFunction value) throws IOException {
      ConcatAggFunction agg = (ConcatAggFunction) value;
      output.writeUTF(agg.getValue());
    }

    public static AggregationFunction read(DataInput input) throws IOException {
      ConcatAggFunction concatAggFunction = new ConcatAggFunction();
      String current = input.readUTF();
      if (!current.isEmpty()) {
        concatAggFunction.enter(current);
      }
      return concatAggFunction;
    }
  }
}
""" 
select concat(personName) from PersonEvent</pre>
						<p>
							Only one <code class="literal">ExtensionAggregationFunction</code> annotation can be specified per class and the annotation is only for use with inlined classes. Using an inline class does not require any compiler configuration.
						</p>
						<p>
							When using <code class="literal">create inlined_class</code> the runtime resolves dependencies on EPL objects at time of deployment (the same as for all EPL objects).
						</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-library"></a>22.5.1.5. Using an Application Class to Provide the Aggregation Single-Function</h4>
								</div>
							</div>
						</div>
						<p>The aggregation function class name as well as the function name for the new aggregation function must be added to the compiler configuration. The configuration shown below is XML however the same options are available through the configuration API. Configuring the function is not necessary when using inlined classes as discussed before.</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-aggregation-function name="concat" 
      forge-class="com.espertech.esper.example.runtimeconfig.MyConcatAggregationFunctionFactory" /&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
						<p>The new aggregation function is now ready to use in a statement:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select concat(symbol) from StockTick#length(3)</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-single-multiparam"></a>22.5.1.6. Aggregation Single-Function: Accepting Multiple Parameters</h4>
								</div>
							</div>
						</div>
						<p>Your plug-in aggregation function may accept multiple parameters. You must provide a different mode however:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">    public AggregationFunctionMode getAggregationFunctionMode() {
        InjectionStrategy injectionStrategy = new InjectionStrategyClassNewInstance(SupportCountBackAggregationFunctionFactory.class);

        AggregationFunctionModeMultiParam multiParam = new AggregationFunctionModeMultiParam();
        multiParam.setInjectionStrategyAggregationFunctionFactory(injectionStrategy);
        
        return multiParam;
    }
</pre>
						<p>
							For instance, assume an aggregation function <code class="literal">rangeCount</code> that counts all values that fall into a range of values. The EPL that calls this function and provides a lower and upper bounds of 1 and 10 is:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select rangeCount(1, 10, myValue) from MyEvent</pre>
						<p>
							The <code class="literal">enter</code> method of the plug-in aggregation function may look as follows:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void enter(Object value)  {
  Object[] params = (Object[]) value;
  int lower = (Integer) params[0];
  int upper = (Integer) params[1];
  int val = (Integer) params[2];
  if ((val &gt;= lower) &amp;&amp; (val &lt;= upper)) {
    count++;
  }
}</pre>
						<p>
							Your plug-in aggregation function may want to validate parameter types or may want to know which parameters are constant-value expressions. Constant-value expressions are evaluated only once by the runtime and could therefore be cached by your aggregation function for performance reasons. The runtime provides constant-value information as part of the <code class="literal">AggregationValidationContext</code> passed to the <code class="literal">validate</code> method.
						</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-single-filter"></a>22.5.1.7. Aggregation Single-Function: The Filter Parameter</h4>
								</div>
							</div>
						</div>
						<p>
							When using <code class="literal">AggregationFunctionModeManaged</code> the runtime already takes care of filters.
						</p>
						<p>
							When using <code class="literal">AggregationFunctionModeMultiParam</code>, the compiler takes the <code class="literal">filter</code> named parameter filter expression as a <code class="literal">boolean</code>-type value and the runtime provides the value to your <code class="literal">enter</code> method as the last value in the parameter array.
						</p>
						<p>
							For instance, assume an aggregation function <code class="literal">concat</code> that receives a <code class="literal">word</code> value and that has a <code class="literal">filter</code> expression as parameters:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select concat(word, filter: word not like '%jim%') from MyWordEvent</pre>
						<p>
							The <code class="literal">enter</code> method of the plug-in aggregation function may look as follows:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void enter(Object value)  {
  Object[] arr = (Object[]) value;
  Boolean pass = (Boolean) arr[1];
  if (pass != null &amp;&amp; pass) {
    buffer.append(arr[0].toString());
  }
}</pre>
						<p>
							Your code can obtain the actual filter expression from the <code class="literal">AggregationValidationContext</code> that is passed to the <code class="literal">validate</code> method and that returns the named parameters via <code class="literal">getNamedParameters</code>.
						</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-single-distinct"></a>22.5.1.8. Aggregation Single-Function: Distinct</h4>
								</div>
							</div>
						</div>
						<p>
							When using <code class="literal">AggregationFunctionModeManaged</code> the runtime already takes care of distinct.
						</p>
						<p>
							When using <code class="literal">AggregationFunctionModeMultiParam</code> your application code must determine and process distinct.
						</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-single-dotmethod"></a>22.5.1.9. Aggregation Single-Function: Dot-Operator Use</h4>
								</div>
							</div>
						</div>
						<p>When the custom aggregation function returns an object as a return value, the EPL can use parenthesis and the dot-operator to invoke methods on the return value.</p>
						<p>
							The following example assumes that the <code class="literal">myAggregation</code> custom aggregation function returns an object that has <code class="literal">getValueOne</code> and <code class="literal">getValueTwo</code> methods:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select (myAggregation(myValue)).getValueOne(),  (myAggregation(myValue)).getValueTwo() from MyEvent</pre>
						<p>
							Since the above EPL aggregates the same value, the runtime internally uses a single aggregation to represent the current value of <code class="literal">myAggregation</code> (and not two instances of the aggregation, even though <code class="literal">myAggregation</code> is listed twice).
						</p>
					</div>
				</div>
				<div class="sect2" lang="en-US">
					<div class="titlepage">
						<div>
							<div>
								<h3 class="title"><a id="custom-aggregation-multi"></a>22.5.2. Aggregation Multi-Function Development</h3>
							</div>
						</div>
					</div>
					<p>This section introduces the aggregation multi-function API. Aggregation multi-functions can offer multiple functions, methods, modifiers or views onto sharable aggregation state. Please refer to the JavaDoc for more complete class and method-level documentation.</p>
					<p>The EPL compiler provides two ways to provide aggregation multi-functions:</p>
					<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
						<ol>
							<li>
								<p>
									An inlined class that is part of the same EPL module or another EPL module, see next under <a class="xref" href="extension.html#custom-aggregation-multi-inlined" title="22.5.2.8. Using an Inlined Class to Provide an Aggregation Multi-Function">Section 22.5.2.8, “Using an Inlined Class to Provide an Aggregation Multi-Function”</a>.
								</p>
								<p>
									An external class that your application provides as part of the application, see below under <a class="xref" href="extension.html#custom-aggregation-multi-config" title="22.5.2.7. Using an Application Class to Provide the Aggregation Multi-Function">Section 22.5.2.7, “Using an Application Class to Provide the Aggregation Multi-Function”</a>.
								</p>
							</li>
						</ol>
					</div>
					<p>In either case, the following steps are required to develop and use a custom aggregation multi-function.</p>
					<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
						<ol>
							<li>
								<p>
									Implement an aggregation multi-function forge by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionForge</code>.
								</p>
							</li>
							<li>
								<p>
									Implement one or more handlers for aggregation functions by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionHandler</code>.
								</p>
							</li>
							<li>
								<p>
									Implement an aggregation state key by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionStateKey</code>.
								</p>
							</li>
							<li>
								<p>
									Implement an aggregation state factory by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionStateFactory</code>.
								</p>
							</li>
							<li>
								<p>
									Implement an aggregation state holder by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionState</code>.
								</p>
							</li>
							<li>
								<p>
									Implement a state accessor factory by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionAccessorFactory</code>.
								</p>
							</li>
							<li>
								<p>
									Implement a state accessor by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionAccessor</code>.
								</p>
							</li>
							<li>
								<p>
									For use with tables, implement an agent factory by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionAgentFactory</code>.
								</p>
							</li>
							<li>
								<p>
									For use with tables, implement an agent by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionAgent</code>.
								</p>
							</li>
							<li>
								<p>
									For use with aggregation methods, implement an aggregation method factory by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionAggregationMethodFactory</code>.
								</p>
							</li>
							<li>
								<p>
									For use with aggregation methods, implement an aggregation method by implementing the interface <code class="literal">com.espertech.esper.common.client.hook.aggmultifunc.AggregationMultiFunctionAggregationMethod</code>.
								</p>
							</li>
							<li>
								<p>
									When using an inlined class, use the <code class="literal">ExtensionAggregationMultiFunction</code> annotation and by providing the function names. When providing external application classes, register the aggregation multi-function forge class with the compiler by supplying one or more function names, via the compiler configuration file or the runtime and static configuration API.
								</p>
							</li>
						</ol>
					</div>
					<p>
						There are two examples for aggregation multi-function. The first example uses inlined classes and can be found at <a class="xref" href="extension.html#custom-aggregation-multi-inlined" title="22.5.2.8. Using an Inlined Class to Provide an Aggregation Multi-Function">Section 22.5.2.8, “Using an Inlined Class to Provide an Aggregation Multi-Function”</a>. The second example for aggregation multi-function is called Cycle-Detect and is used for the step-by-step below.
					</p>
					<p>
						Cycle-Detect takes incoming transaction events that have from-account and to-account fields. The example detects a cycle in the transactions between accounts in order to detect a possible transaction fraud. Please note that the graph and cycle detection logic of the example is not part of the distribution: The example utilizes the <code class="literal">jgrapht</code> library.
					</p>
					<p>
						In the Cycle-Detect example, the vertices of a graph are the account numbers. For example the account numbers <code class="literal">Acct-1</code>, <code class="literal">Acct-2</code> and <code class="literal">Acct-3</code>. In the graph the edges are transaction events that identify a from-account and a to-account. An example edge is <code class="literal">{from:Acct-1, to:Acct-2}</code>. An example cycle is therefore in the three transactions <code class="literal">{from:Acct-1, to:Acct-2}</code>, <code class="literal">{from:Acct-2, to:Acct-3}</code> and <code class="literal">{from:Acct-3, to:Acct-1}</code>.
					</p>
					<p>
						The code for the example aggregation multi-function as shown in this chapter can be found in the Cycle-Detect example in the package <code class="literal">com.espertech.esper.example.cycledetect</code>. The example provides two aggregation functions named <code class="literal">cycledetected</code> and <code class="literal">cycleoutput</code>:
					</p>
					<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
						<ol>
							<li>
								<p>
									The <code class="literal">cycledetected</code> function returns a boolean value whether a graph cycle is found or not.
								</p>
							</li>
							<li>
								<p>
									The <code class="literal">cycleoutput</code> function outputs the vertices (account numbers) that are part of the graph cycle.
								</p>
							</li>
						</ol>
					</div>
					<p>
						In the Cycle-Detect example, the following statement utilizes the two functions <code class="literal">cycledetected</code> and <code class="literal">cycleoutput</code> that share the same graph state to detect a cycle among the last 1000 events:
					</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">@Name('CycleDetector') select cycleoutput() as cyclevertices
from TransactionEvent#length(1000)
having cycledetected(fromAcct, toAcct)</pre>
					<p>If instead the goal is to run graph cycle detection every 1 second (and not upon arrival of a new event), this sample statement uses a pattern to trigger cycle detection:</p>
					<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">@Name('CycleDetector')
select (select cycleoutput(fromAcct, toAcct) from TransactionEvent#length(1000)) as cyclevertices
from pattern [every timer:interval(1)]</pre>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-forge"></a>22.5.2.1. Implementing an Aggregation Multi-Function Forge</h4>
								</div>
							</div>
						</div>
						<p>An aggregation multi-function forge class is a compile-time class responsible for the following functions:</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement the <code class="literal">addAggregationFunction</code> method that receives an invocation for each aggregation function declared in the statement that matches any of the function names provided at configuration time.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">validateGetHandler</code> method that receives an invocation for each aggregation function to be validated in the statement that matches any of the function names provided at configuration time.
									</p>
								</li>
							</ul>
						</div>
						<p>
							Aggregation multi-function factory classes implement the interface <code class="literal">AggregationMultiFunctionForge</code>:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class CycleDetectorAggregationForge implements AggregationMultiFunctionForge { ...</pre>
						<p>The compiler constructs a single instance of the aggregation multi-function forge class that is shared for all aggregation function expressions in a statement that have one of the function names provided in the configuration object.</p>
						<p>
							The compiler invokes the <code class="literal">addAggregationFunction</code> method at the time it compiles a statement. The method receives a declaration-time context object that provides the function name as well as additional information.
						</p>
						<p>
							The sample Cycle-Detect factory class provides an empty <code class="literal">addAggregationFunction</code> method:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void addAggregationFunction(AggregationMultiFunctionDeclarationContext declarationContext) {
    // provides an opportunity to inspect where used
}</pre>
						<p>
							The compiler invokes the <code class="literal">validateGetHandler</code> method at the time of expression validation. It passes a <code class="literal">AggregationMultiFunctionValidationContext</code> validation context object that contains actual parameters expressions. Please see the JavaDoc API documentation for a comprehensive list of validation context information.
						</p>
						<p>
							The <code class="literal">validateGetHandler</code> method must return a handler object the implements the <code class="literal">AggregationMultiFunctionHandler</code> interface. Return a handler object for each aggregation function expression according to the aggregation function name and its parameters that are provided in the validation context.
						</p>
						<p>
							The example <code class="literal">cycledetect</code> function takes two parameters that provide the cycle edge (from-account and to-account):
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public AggregationMultiFunctionHandler validateGetHandler(AggregationMultiFunctionValidationContext validationContext) {
  if (validationContext.getParameterExpressions().length == 2) {
    fromExpression = validationContext.getParameterExpressions()[0];
    toExpression = validationContext.getParameterExpressions()[1];
  }
  return new CycleDetectorAggregationHandler(this, validationContext);
}</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-handlr"></a>22.5.2.2. Implementing an Aggregation Multi-Function Handler</h4>
								</div>
							</div>
						</div>
						<p>
							An aggregation multi-function handler class is a compile-time class that must implement the <code class="literal">AggregationMultiFunctionHandler</code> interface and is responsible for the following functions:
						</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement the <code class="literal">getReturnType</code> method that returns information about the type of return values provided.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">getAggregationStateUniqueKey</code> method that provides a key object used by the compiler to determine which aggregation functions share state.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">getStateMode</code> method that returns information to the compiler that the compiler uses to initialize the state factory at deployment time.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">getAccessorMode</code> method that returns information to the compiler that the compiler uses to initialize the accessor factory at deployment time.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">getAgentMode</code> method that returns information to the compiler that the compiler uses to initialize the agent factory at deployment time, for use with tables.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">getTableReaderMode</code> method that returns information to the compiler that the compiler uses to initialize the table reader factory at deployment time, for use with tables.
									</p>
								</li>
							</ul>
						</div>
						<p>
							In the Cycle-Detect example, the class <code class="literal">CycleDetectorAggregationHandler</code> is the handler for all aggregation functions.
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class CycleDetectorAggregationHandler implements AggregationMultiFunctionHandler { ...</pre>
						<p>
							The <code class="literal">getReturnType</code> method provided by the handler instructs the compiler about the return type of each aggregation accessor. The class <code class="literal">EPChainableType</code> holds return type information.
						</p>
						<p>
							In the Cycle-Detect example the <code class="literal">cycledetected</code> function returns a single boolean value. The <code class="literal">cycleoutput</code> returns a collection of vertices:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public EPChainableType getReturnType() {
    if (validationContext.getFunctionName().toLowerCase(Locale.ENGLISH).equals(CycleDetectorConstant.CYCLEOUTPUT_NAME)) {
        return EPChainableTypeHelper.collectionOfSingleValue((EPTypeClass) forge.getFromExpression().getForge().getEvaluationType());
    }
    return EPChainableTypeHelper.singleValue(Boolean.class);
}</pre>
						<p>
							The compiler invokes the <code class="literal">getAggregationStateUniqueKey</code> method to determine whether multiple aggregation function expressions in the same statement can share the same aggregation state or should receive different aggregation state instances.
						</p>
						<p>
							The <code class="literal">getAggregationStateUniqueKey</code> method must return an instance of <code class="literal">AggregationMultiFunctionStateKey</code>. The compiler uses equals-semantics (the <code class="literal">hashCode</code> and <code class="literal">equals</code> methods) to determine whether multiple aggregation function share the state object. If the key object returned for each aggregation function by the handler is an equal key object then the compiler shares aggregation state between such aggregation functions for the same statement and context partition.
						</p>
						<p>In the Cycle-Detect example the state is shared, which it achieves by simply returning the same key instance:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">private static final AggregationMultiFunctionStateKey CYCLE_KEY = new AggregationMultiFunctionStateKey() {};

public AggregationMultiFunctionStateKey getAggregationStateUniqueKey() {
    return CYCLE_KEY;
}</pre>
						<p>
							The compiler invokes the <code class="literal">getStateMode</code> method to obtain an instance of <code class="literal">AggregationMultiFunctionStateMode</code>. The state mode is responsible to obtaining and configuring an aggregation state factory instance at time of deployment.
						</p>
						<p>In the Cycle-Detect example the method passes the expression evaluators providing the from-account and to-account expressions to the state factory:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public AggregationMultiFunctionStateMode getStateMode() {
    AggregationMultiFunctionStateModeManaged managed = new AggregationMultiFunctionStateModeManaged();
    InjectionStrategyClassNewInstance injection = new InjectionStrategyClassNewInstance(CycleDetectorAggregationStateFactory.class);
    injection.addExpression("from", forge.getFromExpression());
    injection.addExpression("to", forge.getToExpression());
    managed.setInjectionStrategyAggregationStateFactory(injection);
    return managed;
}</pre>
						<p>
							The compiler invokes the <code class="literal">getAccessorMode</code> method to obtain an instance of <code class="literal">AggregationMultiFunctionAccessorMode</code>. The accessor mode is responsible to obtaining and configuring an accessor factory instance at time of deployment.
						</p>
						<p>
							The <code class="literal">getAccessorMode</code> method provides information about the accessor factories according to whether the aggregation function name is <code class="literal">cycledetected</code> or <code class="literal">cycleoutput</code>:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public AggregationMultiFunctionAccessorMode getAccessorMode() {
    Class accessor;
    if (validationContext.getFunctionName().toLowerCase(Locale.ENGLISH).equals(CycleDetectorConstant.CYCLEOUTPUT_NAME)) {
        accessor = CycleDetectorAggregationAccessorOutputFactory.class;
    }
    else {
        accessor = CycleDetectorAggregationAccessorDetectFactory.class;
    }
    AggregationMultiFunctionAccessorModeManaged managed = new AggregationMultiFunctionAccessorModeManaged();
    InjectionStrategyClassNewInstance injection = new InjectionStrategyClassNewInstance(accessor);
    managed.setInjectionStrategyAggregationAccessorFactory(injection);
    return managed;
}</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-statefactory"></a>22.5.2.3. Implementing an Aggregation Multi-Function State Factory</h4>
								</div>
							</div>
						</div>
						<p>
							An aggregation multi-function state factory class must implement the <code class="literal">AggregationMultiFunctionStateFactory</code> interface and is responsible for the following functions:
						</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement the <code class="literal">newState</code> method that returns an aggregation state holder.
									</p>
								</li>
							</ul>
						</div>
						<p>
							The runtime invokes the <code class="literal">newState</code> method to obtain a new aggregation state instance before applying aggregation state. If using <code class="literal">group by</code> in your statement, the runtime invokes the <code class="literal">newState</code> method to obtain a state holder for each group.
						</p>
						<p>
							In the Cycle-Detect example, the class <code class="literal">CycleDetectorAggregationStateFactory</code> is the state factory for all aggregation functions:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class CycleDetectorAggregationStateFactory implements AggregationMultiFunctionStateFactory {

    private ExprEvaluator from;
    private ExprEvaluator to;

    public AggregationMultiFunctionState newState(AggregationMultiFunctionStateFactoryContext ctx) {
        return new CycleDetectorAggregationState(this);
    }

    public void setFrom(ExprEvaluator from) {
        this.from = from;
    }

    public void setTo(ExprEvaluator to) {
        this.to = to;
    }

    public ExprEvaluator getFrom() {
        return from;
    }

    public ExprEvaluator getTo() {
        return to;
    }
}</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-state"></a>22.5.2.4. Implementing an Aggregation Multi-Function State</h4>
								</div>
							</div>
						</div>
						<p>
							An aggregation multi-function state class must implement the <code class="literal">AggregationMultiFunctionState</code> interface and is responsible for the following functions:
						</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement the <code class="literal">applyEnter</code> method that enters events, event properties or computed values.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">applyLeave</code> method that can remove events or computed values.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">clear</code> method to clear state.
									</p>
								</li>
							</ul>
						</div>
						<p>
							In the Cycle-Detect example, the class <code class="literal">CycleDetectorAggregationState</code> is the state for all aggregation functions. Please review the example for more information.
						</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-accessorfactory"></a>22.5.2.5. Implementing an Aggregation Multi-Function Accessor Factory</h4>
								</div>
							</div>
						</div>
						<p>
							An aggregation multi-function accessor factory class must implement the <code class="literal">AggregationMultiFunctionAccessorFactory</code> interface and is responsible for the following functions:
						</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement the <code class="literal">newAccessor</code> method that returns a new accessor.
									</p>
								</li>
							</ul>
						</div>
						<p>
							In the Cycle-Detect example, the class <code class="literal">CycleDetectorAggregationAccessorDetectFactory</code> returns the accessor like so:
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class CycleDetectorAggregationAccessorDetectFactory implements AggregationMultiFunctionAccessorFactory {
    public AggregationMultiFunctionAccessor newAccessor(AggregationMultiFunctionAccessorFactoryContext ctx) {
        return new CycleDetectorAggregationAccessorDetect();
    }
}</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-accessor"></a>22.5.2.6. Implementing an Aggregation Multi-Function Accessor</h4>
								</div>
							</div>
						</div>
						<p>
							An aggregation multi-function accessor class must implement the <code class="literal">AggregationMultiFunctionAccessor</code> interface and is responsible for the following functions:
						</p>
						<div class="itemizedlist">
							<ul compact="compact">
								<li>
									<p>
										Implement the <code class="literal">Object getValue(AggregationMultiFunctionState state, ...)</code> method that returns a result object for the aggregation state.
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">Collection&lt;EventBean&gt; getEnumerableEvents(AggregationMultiFunctionState state, ...)</code> method that returns a collection of events for enumeration, if applicable (or null).
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">EventBean getEnumerableEvent(AggregationMultiFunctionState state, ...)</code> method that returns an event, if applicable (or null).
									</p>
								</li>
								<li>
									<p>
										Implement the <code class="literal">Collection getEnumerableScalar(AggregationMultiFunctionState state, ...)</code> method that returns an event, if applicable (or null).
									</p>
								</li>
							</ul>
						</div>
						<p>
							In the Cycle-Detect example, the class <code class="literal">CycleDetectorAggregationAccessorDetect</code> returns state for the <code class="literal">cycledetected</code> aggregation function and the <code class="literal">CycleDetectorAggregationAccessorOutput</code> returns the state for the <code class="literal">cycleoutput</code> aggregation function.
						</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-config"></a>22.5.2.7. Using an Application Class to Provide the Aggregation Multi-Function</h4>
								</div>
							</div>
						</div>
						<p>An aggregation multi-function configuration can receive one or multiple function names. You must also set a factory class name.</p>
						<p>
							The sample XML snippet below configures an aggregation multi-function that is associated with the function names <code class="literal">func1</code> and <code class="literal">func2</code>.
						</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-aggregation-multifunction 
        function-names="cycledetected,cycleoutput"
        forge-class="com.espertech.esper.example.cycledetect.CycleDetectorAggregationFactory"/&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
						<p>The next example uses the configuration API to register the same:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">String[] functionNames = new String[] {"cycledetected", "cycleoutput"};
ConfigurationPlugInAggregationMultiFunction config = new ConfigurationPlugInAggregationMultiFunction(functionNames, CycleDetectorAggregationFactory.class.getName());
Configuration configuration = new Configuration();
configuration.getCompiler().addPlugInAggregationMultiFunction(config);</pre>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-inlined"></a>22.5.2.8. Using an Inlined Class to Provide an Aggregation Multi-Function</h4>
								</div>
							</div>
						</div>
						<p>
							You may use an inline class that is part of the EPL modules to provide an aggregation multi-function. For more information on inline classes see <a class="xref" href="inlinedclass.html" title="Chapter 18. Inlined Classes">Chapter 18, <i>Inlined Classes</i></a>. Using an inline class does not require any compiler configuration.
						</p>
						<p>
							Specify the <code class="literal">ExtensionAggregationMultiFunction</code> annotation on the class level of the <code class="literal">AggregationMultiFunctionForge</code> implementation class and the function names (names of states and aggregation methods). This annotation instructs the compiler that the inlined class exposes an aggregation multi-function.
						</p>
						<p>This sample EPL includes an inlined class by name TrieAggForge that uses a Trie data structures to store person names. A trie is a tree-like data structure whose nodes store the letters of an alphabet. Here, the Trie stores person names. The implementation uses the Trie provided by the Apache Commons Collections library.</p>
						<p>The following sample EPL uses the Trie to store persons by person name and return a prefix-map, which is a sorted map of all persons that have the same prefix:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">// The PersonEvent provides a person name and person id			
@public @buseventtype create schema PersonEvent(name string, id string);

// This provides the aggregation multi-function 
create inlined_class """
import com.espertech.esper.common.client.*;
import com.espertech.esper.common.client.type.*;
import com.espertech.esper.common.client.hook.aggmultifunc.*;
import com.espertech.esper.common.client.hook.forgeinject.*;
import com.espertech.esper.common.internal.epl.expression.core.*;
import com.espertech.esper.common.internal.rettype.*;
import com.espertech.esper.common.internal.epl.agg.core.*;
import org.apache.commons.collections4.Trie;
import org.apache.commons.collections4.trie.PatriciaTrie;
import java.util.*;
import java.util.function.*;

// We have 3 function names: 
// - "trieState" for use with create-table to hold the Trie
// - "trieEnter" for entering person events into the Trie by person name, for use with into-table aggregation
// - "triePrefixMap" for returning a prefix map of all persons with the same prefix as provided by its parameter
@ExtensionAggregationMultiFunction(names="trieState,trieEnter,triePrefixMap")
/**
 * The trie aggregation forge is the entry point for providing the multi-function aggregation.
 */
public class TrieAggForge implements AggregationMultiFunctionForge {
  public AggregationMultiFunctionHandler validateGetHandler(AggregationMultiFunctionValidationContext validationContext) {
    String name = validationContext.getFunctionName();
    if (name.equals("trieState")) {
      return new TrieAggHandlerTrieState();
    } else if (name.equals("trieEnter")) {
      return new TrieAggHandlerTrieEnter(validationContext.getParameterExpressions());
    } else if (name.equals("triePrefixMap")) {
      return new TrieAggHandlerTriePrefixMap();
    }
    throw new IllegalStateException("Unrecognized name '" + name + "' for use with trie");
  }
  
  /**
   * This handler handles the "trieState"-type table column, for use with create-table.
   */
  public static class TrieAggHandlerTrieState implements AggregationMultiFunctionHandler {
    public EPChainableType getReturnType() {
      return EPChainableTypeHelper.singleValue(Trie.class);
    }

    public AggregationMultiFunctionStateKey getAggregationStateUniqueKey() {
      return new AggregationMultiFunctionStateKey() {};
    }

    public AggregationMultiFunctionStateMode getStateMode() {
      InjectionStrategyClassNewInstance injection = new InjectionStrategyClassNewInstance(TrieAggStateFactory.class);
      return new AggregationMultiFunctionStateModeManaged(injection);
    }

    public AggregationMultiFunctionAccessorMode getAccessorMode() {
      // accessor that returns the trie itself
      InjectionStrategyClassNewInstance injection = new InjectionStrategyClassNewInstance(TrieAggAccessorFactory.class);
      return new AggregationMultiFunctionAccessorModeManaged(injection);
    }

    public AggregationMultiFunctionAgentMode getAgentMode() {
      throw new UnsupportedOperationException("Trie aggregation access is only by the 'triePrefixMap' method");
    }

    public AggregationMultiFunctionAggregationMethodMode getAggregationMethodMode(AggregationMultiFunctionAggregationMethodContext ctx) {
      throw new UnsupportedOperationException("Trie aggregation access is only by the 'triePrefixMap' method");
    }
  }
  
  /**
   * This handler handles the "trieEnter"-operation that updates trie state, for use with into-table aggregation
   */
  public static class TrieAggHandlerTrieEnter implements AggregationMultiFunctionHandler {
    private final ExprNode[] parameters;
    
    public TrieAggHandlerTrieEnter(ExprNode[] parameters) {
      this.parameters = parameters;
    }

    public EPChainableType getReturnType() {
      return EPChainableTypeHelper.singleValue(Trie.class); // we return the Trie itself
    }

    public AggregationMultiFunctionStateKey getAggregationStateUniqueKey() {
      throw new UnsupportedOperationException("Not a trie state");
    }

    public AggregationMultiFunctionStateMode getStateMode() {
      throw new UnsupportedOperationException("Not a trie state");
    }

    public AggregationMultiFunctionAccessorMode getAccessorMode() {
      // accessor that returns the trie itself
      InjectionStrategyClassNewInstance injection = new InjectionStrategyClassNewInstance(TrieAggAccessorFactory.class);
      return new AggregationMultiFunctionAccessorModeManaged(injection);
    }

    public AggregationMultiFunctionAgentMode getAgentMode() {
      if (parameters.length != 1 || ((EPTypeClass) parameters[0].getForge().getEvaluationType()).getType() != String.class) {
        throw new IllegalArgumentException("Requires a single parameter returing a string value");
      }
      InjectionStrategyClassNewInstance injection = new InjectionStrategyClassNewInstance(TrieAggAgentFactory.class);
      injection.addExpression("keyExpression", parameters[0]);
      return new AggregationMultiFunctionAgentModeManaged(injection);
    }

    public AggregationMultiFunctionAggregationMethodMode getAggregationMethodMode(AggregationMultiFunctionAggregationMethodContext ctx) {
      throw new UnsupportedOperationException("Trie aggregation access is only by the 'triePrefixMap' method");
    }
  }
  
  /**
   * This handler handles the "triePrefixMap" accessor for returning a prefix map of same-prefix person events
   */
  public static class TrieAggHandlerTriePrefixMap implements AggregationMultiFunctionHandler {
    public EPChainableType getReturnType() {
      return EPChainableTypeHelper.singleValue(Map.class);
    }
    
    public AggregationMultiFunctionStateKey getAggregationStateUniqueKey() {
      throw new UnsupportedOperationException("Not implemented for 'triePrefixMap' trie method");
    }

    public AggregationMultiFunctionStateMode getStateMode() {
      throw new UnsupportedOperationException("Not implemented for 'triePrefixMap' trie method");
    }

    public AggregationMultiFunctionAccessorMode getAccessorMode() {
      throw new UnsupportedOperationException("Not implemented for 'triePrefixMap' trie method");
    }

    public AggregationMultiFunctionAgentMode getAgentMode() {
      throw new UnsupportedOperationException("Not implemented for 'triePrefixMap' trie method");
    }

    public AggregationMultiFunctionAggregationMethodMode getAggregationMethodMode(AggregationMultiFunctionAggregationMethodContext ctx) {
      if (ctx.getParameters().length != 1 || ((EPTypeClass) ctx.getParameters()[0].getForge().getEvaluationType()).getType() != String.class) {
        throw new IllegalArgumentException("Requires a single parameter returning a string value");
      }
      InjectionStrategyClassNewInstance injection = new InjectionStrategyClassNewInstance(TrieAggMethodFactoryPrefixMap.class);
      injection.addExpression("keyExpression", ctx.getParameters()[0]);
      return new AggregationMultiFunctionAggregationMethodModeManaged(injection);
    }
  }
  
  /**
   * The agent state factory is responsible for producing a state holder that holds the trie state
   */
  public static class TrieAggStateFactory implements AggregationMultiFunctionStateFactory {
    public AggregationMultiFunctionState newState(AggregationMultiFunctionStateFactoryContext ctx) {
      return new TrieAggState();
    }
  }
  
  /**
   * The agent state is the state holder that holds the trie state
   */
  public static class TrieAggState implements AggregationMultiFunctionState {
    private final Trie&lt;String, List&lt;Object&gt;&gt; trie = new PatriciaTrie&lt;&gt;();
    
    public void applyEnter(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) {
      throw new UnsupportedOperationException("Not used since the agent updates the table");
    }
    
    public void applyLeave(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) {
      throw new UnsupportedOperationException("Not used since the agent updates the table");
    }
    
    public void clear() {
      trie.clear();
    }

    public void add(String key, Object underlying) {
      List&lt;Object&gt; existing = (List&lt;Object&gt;) trie.get(key);
      if (existing != null) {
        existing.add(underlying);
        return;
      }
      List&lt;Object&gt; events = new ArrayList&lt;&gt;(2);
      events.add(underlying);
      trie.put(key, events);
    }
    
    public void remove(String key, Object underlying) {
      List&lt;Object&gt; existing = (List&lt;Object&gt;) trie.get(key);
      if (existing != null) {
        existing.remove(underlying);
        if (existing.isEmpty()) {
          trie.remove(key);
        }
      }
    }
  }
  
  /**
   * The accessor factory is responsible for producing an accessor that returns the result of the trie table column when accessed without an aggregation method
   */
  public static class TrieAggAccessorFactory implements AggregationMultiFunctionAccessorFactory {
    public AggregationMultiFunctionAccessor newAccessor(AggregationMultiFunctionAccessorFactoryContext ctx) {
      return new TrieAggAccessor();
    }
  }
  
  /**
   * The accessor returns the result of the trie table column when accessed without an aggregation method
   */
  public static class TrieAggAccessor implements AggregationMultiFunctionAccessor {
    // This is the value return when just referring to the trie table column by itself without a method name such as "prefixMap".
    public Object getValue(AggregationMultiFunctionState state, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {
      TrieAggState trie = (TrieAggState) state;
      return trie.trie;
    }
  }
  
  /**
   * The agent factory is responsible for producing an agent that handles all changes to the trie table column.
   */
  public static class TrieAggAgentFactory implements AggregationMultiFunctionAgentFactory {
    private ExprEvaluator keyExpression;
    
    public void setKeyExpression(ExprEvaluator keyExpression) {
      this.keyExpression = keyExpression;
    }
    
    public AggregationMultiFunctionAgent newAgent(AggregationMultiFunctionAgentFactoryContext ctx) {
      return new TrieAggAgent(this);
    }
  }
  
  /**
   * The agent is responsible for all changes to the trie table column.
   */
  public static class TrieAggAgent implements AggregationMultiFunctionAgent {
    private final TrieAggAgentFactory factory;
    
    public TrieAggAgent(TrieAggAgentFactory factory) {
      this.factory = factory;
    }
    
    public void applyEnter(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext, AggregationRow row, int column) {
      String key = (String) factory.keyExpression.evaluate(eventsPerStream, true, exprEvaluatorContext);
      TrieAggState trie = (TrieAggState) row.getAccessState(column);
      trie.add(key, eventsPerStream[0].getUnderlying());
    }

    public void applyLeave(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext, AggregationRow row, int column) {
      String key = (String) factory.keyExpression.evaluate(eventsPerStream, false, exprEvaluatorContext);
      TrieAggState trie = (TrieAggState) row.getAccessState(column);
      trie.remove(key, eventsPerStream[0].getUnderlying());
    }
  }
  
  /**
   * The aggregation method factory is responsible for producing an aggregation method for the "trie" return result of the trie table column.
   */
  public static class TrieAggMethodFactoryTrieColumn implements AggregationMultiFunctionAggregationMethodFactory {
    public AggregationMultiFunctionAggregationMethod newMethod(AggregationMultiFunctionAggregationMethodFactoryContext context) {
      return new AggregationMultiFunctionAggregationMethod() {
        public Object getValue(int aggColNum, AggregationRow row, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {
          TrieAggState trie = (TrieAggState) row.getAccessState(aggColNum);
          return trie.trie;
        }
      };
    }
  }
  
  /**
   * The aggregation method factory is responsible for producing an aggregation method for the "triePrefixMap" expression of the trie table column.
   */
  public static class TrieAggMethodFactoryPrefixMap implements AggregationMultiFunctionAggregationMethodFactory {
    private ExprEvaluator keyExpression;
    
    public void setKeyExpression(ExprEvaluator keyExpression) {
      this.keyExpression = keyExpression;
    }

    public AggregationMultiFunctionAggregationMethod newMethod(AggregationMultiFunctionAggregationMethodFactoryContext context) {
      return new TrieAggMethodPrefixMap(this);
    }
  }
  
  /**
   * The aggregation method is responsible for the "triePrefixMap" expression result of the trie table column.
   */
  public static class TrieAggMethodPrefixMap implements AggregationMultiFunctionAggregationMethod {
    private final TrieAggMethodFactoryPrefixMap factory;
    
    public TrieAggMethodPrefixMap(TrieAggMethodFactoryPrefixMap factory) {
      this.factory = factory;
    }
    
    public Object getValue(int aggColNum, AggregationRow row, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {
      String key = (String) factory.keyExpression.evaluate(eventsPerStream, false, exprEvaluatorContext);
      TrieAggState trie = (TrieAggState) row.getAccessState(aggColNum);
      return trie.trie.prefixMap(key);
    }
  }
}
""";

// We use a table to store the Trie. The Trie is effectively a Trie&lt;String, List&lt;PersonEvent&gt;&gt; holding a list of person events in branch and leaf nodes.
@name('table') create table TableWithTrie(nameTrie trieState(string));

// We aggregate directly into the table using the person name as the Trie key and the event as value
@Priority(1) into table TableWithTrie select trieEnter(name) as nameTrie from PersonEvent;

// For each person output the prefix map, a sorted map (SortedMap&lt;String, List&lt;PersonEvent&gt;&gt;) with the same prefixes as the person name
@Priority(0) @name('s0') select TableWithTrie.nameTrie.triePrefixMap(name) from PersonEvent;</pre>
						<p>
							Only one <code class="literal">ExtensionAggregationMultiFunction</code> annotation can be specified per class and the annotation is only for use with inlined classes. Using an inline class does not require any compiler configuration.
						</p>
						<p>When using create inlined_class the runtime resolves dependencies on EPL objects at time of deployment (the same as for all EPL objects).</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-threadsafety"></a>22.5.2.9. Aggregation Multi-Function Thread Safety</h4>
								</div>
							</div>
						</div>
						<p>
							The runtime shares an <code class="literal">AggregationAccessor</code> instance between threads. The accessor should be designed stateless and should not use any locking of any kind in the <code class="literal">AggregationAccessor</code> implementation unless your implementation uses other state. Since the runtime passes an aggregation state instance to the accessor it is thread-safe as long as it relies only on the aggregation state passed to it.
						</p>
						<p>
							The runtime does not share an <code class="literal">AggregationState</code> instance between threads. There is no need to use locking of any kind in the <code class="literal">AggregationState</code> implementation unless your implementation uses other state.
						</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-table"></a>22.5.2.10. Aggregation Multi-Function Use With Tables</h4>
								</div>
							</div>
						</div>
						<p>Tables allow columns to hold aggregation state including the state for multi-function aggregations. This section provides API pointers.</p>
						<p>
							When a statement accesses a table column that declares aggregation state of a multi-function aggregation, the <code class="literal">AggregationMultiFunctionValidationContext</code> contains an <code class="literal">optionalTableColumnRead</code> field that provides information about the table column.
						</p>
						<p>
							To find out the statement type, such as to determine whether the current statement is a <code class="literal">create-table</code> statement, use <code class="literal">context.getValidationContext().getExprEvaluatorContext().getStatementType()</code>.
						</p>
						<p>
							To find out whether the statement aggregates into a table, use <code class="literal">context.getValidationContext().getIntoTableName()</code> that returns the table name or null if not aggregating into a table.
						</p>
						<p>
							The compiler uses <code class="literal">AggregationMultiFunctionStateKey</code> to determine whether an aggregation function listed with <code class="literal">into table</code> is compatible with the aggregation type that a table column declares. The <code class="literal">equals</code> method of the object must return true for compatible and false for incompatible.
						</p>
						<p>Your handler may provide a agent and aggregation method modes. Please follow the JavaDoc or inspect the regression test suite.</p>
					</div>
					<div class="sect3" lang="en-US">
						<div class="titlepage">
							<div>
								<div>
									<h4 class="title"><a id="custom-aggregation-multi-filter"></a>22.5.2.11. Aggregation Multi-Function Use Filter Expression</h4>
								</div>
							</div>
						</div>
						<p>
							The <code class="literal">filter</code> expression is passed to you in <code class="literal">PlugInAggregationMultiFunctionValidationContext</code> as part of <code class="literal">getNamedParameters</code> under the name <code class="literal">filter</code>. When use with tables the filter expression is part of <code class="literal">PlugInAggregationMultiFunctionAgentContext</code>.
						</p>
						<p>Your application must invoke the filter expression as the runtime does not evaluate the filter expression for you. For example:</p>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">ExprEvaluator filterEval = validationContext.getNamedParameters().get("filter").get(0).getExprEvaluator();</pre>
						<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void applyEnter(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) {
  Boolean pass = (Boolean) filterEval.evaluate(eventsPerStream, true, exprEvaluatorContext); // note: pass "false" for applyLeave
  if (pass != null &amp;&amp; pass) {
    Object value = valueEval.evaluate(eventsPerStream, true, exprEvaluatorContext); // note: pass "false" for applyLeave
    // do something
  }
}</pre>
					</div>
				</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="custom-pattern-guard"></a>22.6. Pattern Guard</h2>
					</div>
				</div>
			</div>
			<a id="d0e55039" class="indexterm"></a><a id="d0e55044" class="indexterm"></a>
			<p>Pattern guards are pattern objects that control the lifecycle of the guarded sub-expression, and can filter the events fired by the subexpression.</p>
			<p>The following steps are required to develop and use a custom guard object.</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
				<ol>
					<li>
						<p>Implement a guard forge class, responsible for compile-time guard information.</p>
					</li>
					<li>
						<p>Implement a guard factory class, responsible for creating guard object instances at runtime.</p>
					</li>
					<li>
						<p>Implement a guard class (used at runtime).</p>
					</li>
					<li>
						<p>Register the guard forge class with the compiler by supplying a namespace and name, via the compiler configuration.</p>
					</li>
				</ol>
			</div>
			<p>
				The code for the example guard object as shown in this chapter can be found in the test source folder in the package <code class="literal">com.espertech.esper.regressionlib.support.extend.pattern</code> by the name <code class="literal">MyCountToPatternGuardForge</code>. The sample guard discussed here counts the number of events occurring up to a maximum number of events, and end the sub-expression when that maximum is reached.
			</p>
			<p>
				Some of the APIs that you use to implement a pattern guard are internal APIs and are not stable and may change between releases. The <code class="literal">client</code> package contains all the stable interface classes.
			</p>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-guard-forge-implementing"></a>22.6.1. Implementing a Guard Forge</h3>
						</div>
					</div>
				</div>
				<p>A guard forge class is only used by the compiler and is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Implement a <code class="literal">setGuardParameters</code> method that takes guard parameters, which are themselves expressions.
							</p>
						</li>
						<li>
							<p>
								Implement a <code class="literal">collectSchedule</code> method that collects guard schedule objects if any.
							</p>
						</li>
						<li>
							<p>
								Implement a <code class="literal">makeCodegen</code> method that provides the code to construct a guard factory at time of deployment.
							</p>
						</li>
					</ul>
				</div>
				<p>
					Guard forge classes implement the <code class="literal">GuardForge</code>:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyCountToPatternGuardForge implements GuardForge { ...</pre>
				<p>The compiler constructs one instance of the guard forge class for each time the guard is listed in a statement.</p>
				<p>
					The guard forge class implements the <code class="literal">setGuardParameters</code> method that is passed the parameters to the guard as supplied by the statement. It verifies the guard parameters, similar to the code snippet shown next. Our example counter guard takes a single numeric parameter:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void setGuardParameters(List&lt;ExprNode&gt; guardParameters, MatchedEventConvertorForge convertor, StatementCompileTimeServices services) throws GuardParameterException {
    String message = "Count-to guard takes a single integer-value expression as parameter";
    if (guardParameters.size() != 1) {
        throw new GuardParameterException(message);
    }

    Class paramType = guardParameters.get(0).getForge().getEvaluationType();
    if (paramType != Integer.class &amp;&amp; paramType != int.class) {
        throw new GuardParameterException(message);
    }
        
    this.numCountToExpr = guardParameters.get(0);
    this.convertor = convertor;
}</pre>
				<p>
					The <code class="literal">makeCodegen</code> method is called by the compiler to receive the code that builds a guard factory. Use the <code class="literal">SAIFFInitializeBuilder</code> to build factory initialization code:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public CodegenExpression makeCodegen(CodegenMethodScope parent, SAIFFInitializeSymbol symbols, CodegenClassScope classScope) {
    SAIFFInitializeBuilder builder = new SAIFFInitializeBuilder(MyCountToPatternGuardFactory.class, this.getClass(), "guardFactory", parent, symbols, classScope);
    return builder.exprnode("numCountToExpr", numCountToExpr)
                .expression("convertor", convertor.makeAnonymous(builder.getMethod(), classScope))
                .build();
}</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-guard-factory-implementing"></a>22.6.2. Implementing a Guard Factory</h3>
						</div>
					</div>
				</div>
				<p>A guard factory class is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Implement a <code class="literal">makeGuard</code> method that constructs a new guard instance.
							</p>
						</li>
					</ul>
				</div>
				<p>
					Guard factory classes implements the <code class="literal">GuardFactory</code>:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyCountToPatternGuardFactory implements GuardFactory { ...</pre>
				<p>The runtime obtains an instance of the guard factory class at time of deployment.</p>
				<p>
					The <code class="literal">makeGuard</code> method is called by the runtime to create a new guard instance. The example <code class="literal">makeGuard</code> method shown below passes the maximum count of events to the guard instance. It also passes a <code class="literal">Quitable</code> implementation to the guard instance. The guard uses <code class="literal">Quitable</code> to indicate that the sub-expression contained within must stop (quit) listening for events.
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public Guard makeGuard(PatternAgentInstanceContext context, MatchedEventMap beginState, Quitable quitable, Object guardState) {
    EventBean[] events = convertor == null ? null : convertor.convert(beginState);
    Object parameter = PatternExpressionUtil.evaluateChecked("Count-to guard", numCountToExpr, events, context.getAgentInstanceContext());
    if (parameter == null) {
        throw new EPException("Count-to guard parameter evaluated to a null value");
    }

    Integer numCountTo = (Integer) parameter;
    return new MyCountToPatternGuard(numCountTo, quitable);
}</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-guard-implementing"></a>22.6.3. Implementing a Guard Class</h3>
						</div>
					</div>
				</div>
				<p>A guard class has the following responsibilities:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Provides a <code class="literal">startGuard</code> method that initalizes the guard.
							</p>
						</li>
						<li>
							<p>
								Provides a <code class="literal">stopGuard</code> method that stops the guard, called by the runtime when the whole pattern is stopped, or the sub-expression containing the guard is stopped.
							</p>
						</li>
						<li>
							<p>
								Provides an <code class="literal">inspect</code> method that the pattern runtime invokes to determine if the guard lets matching events pass for further evaluation by the containing expression.
							</p>
						</li>
					</ul>
				</div>
				<p>
					Guard classes implement the <code class="literal">GuardSupport</code> interface as shown here:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyCountToPatternGuard implements Guard {</pre>
				<p>The compiler invokes the guard factory class to construct an instance of the guard class for each new sub-expression instance within a statement.</p>
				<p>
					A guard class must provide an implementation of the <code class="literal">startGuard</code> method that the runtime invokes to start a guard instance. In our example, the method resets the guard's counter to zero:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void startGuard() {
  counter = 0;
}</pre>
				<p>
					The runtime invokes the <code class="literal">inspect</code> method for each time the sub-expression indicates a new event result. Our example guard needs to count the number of events matched, and quit if the maximum number is reached:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public boolean inspect(MatchedEventMap matchEvent) {
  counter++;
  if (counter &gt; numCountTo) {
    quitable.guardQuit();
    return false;
  }
  return true;
}</pre>
				<p>
					The <code class="literal">inspect</code> method returns true for events that pass the guard, and false for events that should not pass the guard.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-guard-config"></a>22.6.4. Configuring Guard Namespace and Name</h3>
						</div>
					</div>
				</div>
				<p>The guard factory class name as well as the namespace and name for the new guard must be added to the compiler configuration. The configuration shown below is XML however the same options are available through the configuration API:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-pattern-guard namespace="myplugin" name="count_to" 
        forge-class="com.espertech.esper.regressionlib.support.extend.pattern.MyCountToPatternGuardForge"/&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
				<p>The new guard is now ready to use in a statement. The next pattern statement detects the first 10 MyEvent events:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from pattern [(every MyEvent) where myplugin:count_to(10)]</pre>
				<p>
					Note that the <code class="literal">every</code> keyword was placed within parentheses to ensure the guard controls the repeated matching of events.
				</p>
			</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="custom-pattern-observer"></a>22.7. Pattern Observer</h2>
					</div>
				</div>
			</div>
			<a id="d0e55237" class="indexterm"></a><a id="d0e55242" class="indexterm"></a>
			<p>
				Pattern observers are pattern objects that are executed as part of a pattern expression and can observe events or test conditions. Examples for built-in observers are <code class="literal">timer:at</code> and <code class="literal">timer:interval</code>. Some suggested uses of observer objects are:
			</p>
			<div class="itemizedlist">
				<ul compact="compact">
					<li>
						<p>Implement custom scheduling logic using the runtime's own scheduling and timer services</p>
					</li>
					<li>
						<p>Test conditions related to prior events matching an expression</p>
					</li>
				</ul>
			</div>
			<p>The following steps are required to develop and use a custom observer object within pattern statements:</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
				<ol>
					<li>
						<p>Implement an observer forge class, which is used by the compiler only and is responsible for validating parameters and for initializing an observer factory.</p>
					</li>
					<li>
						<p>Implement an observer factory class, responsible for creating observer object instances.</p>
					</li>
					<li>
						<p>Implement an observer class.</p>
					</li>
					<li>
						<p>Register an observer factory class with the compiler by supplying a namespace and name, via the compiler configuration file or the configuration API.</p>
					</li>
				</ol>
			</div>
			<p>
				The code for the example observer object as shown in this chapter can be found in the test source folder in package <code class="literal">com.espertech.esper.regression.client</code> by the name <code class="literal">MyFileExistsObserver</code>. The sample observer discussed here very simply checks if a file exists, using the filename supplied by the pattern statement, and via the <code class="literal">java.io.File</code> class.
			</p>
			<p>
				Some of the APIs that you use to implement a pattern observer are internal APIs and are not stable and may change between releases. The <code class="literal">client</code> package contains all the stable interface classes.
			</p>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-observer-forge-implementing"></a>22.7.1. Implementing an Observer Forge</h3>
						</div>
					</div>
				</div>
				<p>An observer forge class is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Implement a <code class="literal">setObserverParameters</code> method that takes observer parameters, which are themselves expressions.
							</p>
						</li>
						<li>
							<p>
								Implement a <code class="literal">collectSchedule</code> method that collects observer schedule objects if any.
							</p>
						</li>
						<li>
							<p>
								Implement a <code class="literal">makeCodegen</code> method that provides the code to construct an observer factory at time of deployment.
							</p>
						</li>
					</ul>
				</div>
				<p>
					Observer forge classes implement the <code class="literal">ObserverForge</code> interface:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyFileExistsObserverForge implements ObserverForge { ...</pre>
				<p>The compiler constructs one instance of the observer forge class for each time the observer is listed in a statement.</p>
				<p>
					The observer forge class implements the <code class="literal">setObserverParameters</code> method that is passed the parameters to the observer as supplied by the statement. It verifies the observer parameters, similar to the code snippet shown next. Our example file-exists observer takes a single string parameter:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void setObserverParameters(List&lt;ExprNode&gt; observerParameters, MatchedEventConvertorForge convertor, ExprValidationContext validationContext) throws ObserverParameterException {
    String message = "File exists observer takes a single string filename parameter";
    if (observerParameters.size() != 1) {
        throw new ObserverParameterException(message);
    }
    if (!(observerParameters.get(0).getForge().getEvaluationType() == String.class)) {
        throw new ObserverParameterException(message);
    }

    this.filenameExpression = observerParameters.get(0);
    this.convertor = convertor;
}</pre>
				<p>
					The compiler calls the <code class="literal">makeCodegen</code> method to provide code that initializes the observer factory at time of deployment. It uses the <code class="literal">SAIFFInitializeBuilder</code> to build the code.
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public CodegenExpression makeCodegen(CodegenMethodScope parent, SAIFFInitializeSymbol symbols, CodegenClassScope classScope) {
    SAIFFInitializeBuilder builder = new SAIFFInitializeBuilder(MyFileExistsObserverFactory.class, this.getClass(), "observerFactory", parent, symbols, classScope);
    return builder.exprnode("filenameExpression", filenameExpression)
            .expression("convertor", convertor.makeAnonymous(builder.getMethod(), classScope))
            .build();
}
</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-observer-factory-implementing"></a>22.7.2. Implementing an Observer Factory</h3>
						</div>
					</div>
				</div>
				<p>An observer factory class is responsible for the following functions:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Implement a <code class="literal">makeObserver</code> method that returns a new observer instance.
							</p>
						</li>
					</ul>
				</div>
				<p>
					Observer factory classes implement the <code class="literal">ObserverFactory</code>:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyFileExistsObserverFactory implements ObserverFactory { ...</pre>
				<p>The runtime obtains an instance of the observer factory class at time of deployment.</p>
				<p>
					The runtime calls the <code class="literal">makeObserver</code> method to create a new observer instance. The example <code class="literal">makeObserver</code> method shown below passes parameters to the observer instance:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public EventObserver makeObserver(PatternAgentInstanceContext context, MatchedEventMap beginState, ObserverEventEvaluator observerEventEvaluator, Object observerState, boolean isFilterChildNonQuitting) {
    EventBean[] events = convertor == null ? null : convertor.convert(beginState);
    Object filename = PatternExpressionUtil.evaluateChecked("File-exists observer ", filenameExpression, events, context.getAgentInstanceContext());
    if (filename == null) {
        throw new EPException("Filename evaluated to null");
    }
    return new MyFileExistsObserver(beginState, observerEventEvaluator, filename.toString());
}</pre>
				<p>
					The <code class="literal">ObserverEventEvaluator</code> parameter allows an observer to indicate events, and to indicate change of truth value to permanently false. Use this interface to indicate when your observer has received or witnessed an event, or changed it's truth value to true or permanently false.
				</p>
				<p>
					The <code class="literal">MatchedEventMap</code> parameter provides a Map of all matching events for the expression prior to the observer's start. For example, consider a pattern as below:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">a=MyEvent -&gt; myplugin:my_observer(...)</pre>
				<p>
					The above pattern tagged the MyEvent instance with the tag "a". The runtime starts an instance of <code class="literal">my_observer</code> when it receives the first MyEvent. The observer can query the <code class="literal">MatchedEventMap</code> using "a" as a key and obtain the tagged event.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-observer-implementing"></a>22.7.3. Implementing an Observer Class</h3>
						</div>
					</div>
				</div>
				<p>An observer class has the following responsibilities:</p>
				<div class="itemizedlist">
					<ul compact="compact">
						<li>
							<p>
								Provides a <code class="literal">startObserve</code> method that starts the observer.
							</p>
						</li>
						<li>
							<p>
								Provides a <code class="literal">stopObserve</code> method that stops the observer, called by the runtime when the whole pattern is stopped, or the sub-expression containing the observer is stopped.
							</p>
						</li>
					</ul>
				</div>
				<p>
					Observer classes subclass <code class="literal">com.espertech.esper.pattern.observer.ObserverSupport</code> as shown here:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyFileExistsObserver implements EventObserver { ...</pre>
				<p>The runtime invokes the observer factory class to construct an instance of the observer class for each new sub-expression instance within a statement.</p>
				<p>
					An observer class must provide an implementation of the <code class="literal">startObserve</code> method that the runtime invokes to start an observer instance. In our example, the observer checks for the presence of a file and indicates the truth value to the remainder of the expression:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public void startObserve() {
  File file = new File(filename);
  if (file.exists()) {
    observerEventEvaluator.observerEvaluateTrue(beginState);
  } 
  else {
    observerEventEvaluator.observerEvaluateFalse(); 
  }
}</pre>
				<p>
					Note the observer passes the <code class="literal">ObserverEventEvaluator</code> an instance of <code class="literal">MatchedEventMap</code>. The observer can also create one or more new events and pass these events through the Map to the remaining expressions in the pattern.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-pattern-observer-config"></a>22.7.4. Configuring Observer Namespace and Name</h3>
						</div>
					</div>
				</div>
				<p>The observer factory class name as well as the namespace and name for the new observer must be added to the compiler configuration via the configuration API or using the XML configuration file. The configuration shown below is XML however the same options are available through the configuration API:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-pattern-observer namespace="myplugin" name="file_exists" 
      forge-class="com.espertech.esper.regressionlib.support.extend.pattern.MyFileExistsObserverForge" /&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
				<p>The new observer is now ready to use in a statement. The next pattern statement checks every 10 seconds if the given file exists, and indicates to the listener when the file is found.</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select * from pattern [every timer:interval(10 sec) -&gt; myplugin:file_exists("myfile.txt")]</pre>
			</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="custom-datetimemethod"></a>22.8. Date-Time Method</h2>
					</div>
				</div>
			</div>
			<a id="d0e55450" class="indexterm"></a><a id="d0e55455" class="indexterm"></a>
			<p>Your application can provide additional date-time methods by implementing the extension API as shown below. The steps are as follows:</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
				<ol>
					<li>
						<p>
							Implement the <code class="literal">DateTimeMethodForgeFactory</code> interface (package <code class="literal">com.espertech.esper.common.client.hook.datetimemethod</code>) that the compiler invokes for validation and to receive information on the public static methods that your application exposes that provide the date-time method logic.
						</p>
					</li>
					<li>
						<p>Implement a static method (or multiple static methods) that receives the respective date-time value and additional parameters, if any, and that may return a new value, following the rules outlined below.</p>
					</li>
					<li>
						<p>
							Add the class name of the <code class="literal">DateTimeMethodForgeFactory</code> implementation to the compiler configuration.
						</p>
					</li>
					<li>
						<p>Use the new date-time method(s).</p>
					</li>
				</ol>
			</div>
			<p>The EPL compiler distinguishes between two types of date-time methods:</p>
			<div class="itemizedlist">
				<ul>
					<li>
						<p>
							A <span class="emphasis"><em>modifying</em></span> date-time method modifies the date-time value, while the type of the result is the same as the type of the date-time value (i.e. input and result is a <code class="literal">Calendar</code> or <code class="literal">LocalDateTime</code> or other value).
						</p>
					</li>
					<li>
						<p>
							A <span class="emphasis"><em>reformatting</em></span> date-time method transforms the date-time value into a result that has a different return type.
						</p>
					</li>
				</ul>
			</div>
			<p>
				The example herein builds a value-changing date-time method by name <code class="literal">roll</code> that rolls a field forward or backward and that receives the name of the field and an up/down flag as parameters.
			</p>
			<p>
				The second example herein builds a reformatting date-time method by name <code class="literal">asArrayOfString</code> that returns an array of strings containing the day, month and year values of the date-time value.
			</p>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-datetimemethod-stepone"></a>22.8.1. Implement the <code class="literal">DateTimeMethodForgeFactory</code> Interface</h3>
						</div>
					</div>
				</div>
				<p>
					The implementation of the <code class="literal">DateTimeMethodForgeFactory</code> interface is responsible for:
				</p>
				<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
					<ol>
						<li>
							<p>
								The <code class="literal">initialize</code> method returns the available footprints.
							</p>
						</li>
						<li>
							<p>
								The <code class="literal">validate</code> method may validate actual provided parameters and always returns either a <code class="literal">DateTimeMethodOpsModify</code> (for modify) or a <code class="literal">DateTimeMethodOpsReformat</code> (for reformat).
							</p>
						</li>
					</ol>
				</div>
				<p>
					The EPL compiler calls the <code class="literal">initialize</code> method to obtain the allowed footprints. It compares the footprints to the number and type of parameters actually provided.
				</p>
				<p>For example, if there is a single footprint with no parameters, use this:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">DotMethodFP[] footprints = new DotMethodFP[] {
    new DotMethodFP(DotMethodFPInputEnum.SCALAR_ANY)
  };
return new DateTimeMethodDescriptor(footprints);</pre>
				<p>For example, if there is a single footprint with a single string-type parameter, use this:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">DotMethodFP[] footprints = new DotMethodFP[] {
  new DotMethodFP(DotMethodFPInputEnum.SCALAR_ANY,
      new DotMethodFPParam("provide a descriptive name of parameter", EPLExpressionParamType.SPECIFIC, String.class)
    )
  };</pre>
				<p>
					In the case that the date-time method modifies the date-time value, make the <code class="literal">validate</code> method returns an instance of <code class="literal">DateTimeMethodModifyOps</code>.
				</p>
				<p>
					In the case that the date-time method reformats the date-time value, make the <code class="literal">validate</code> method returns an instance of <code class="literal">DateTimeMethodReformatOps</code>.
				</p>
				<p>
					Use the <code class="literal">DateTimeMethodModeStaticMethod</code> class to provide the class and the name of the public static method providing the respective operation.
				</p>
				<p>It is not required to provide a static method for each of the different types of date-time values. You may leave an operation at a null-value to indicate it is not provided for that date-time value type.</p>
				<p>
					The following class handles the new <code class="literal">roll</code> date-time method, which has single footprint that has a string-type and a boolean-type parameter:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyLocalDTMForgeFactoryRoll implements DateTimeMethodForgeFactory {
  private final static DotMethodFP[] FOOTPRINTS = new DotMethodFP[]{
    new DotMethodFP(DotMethodFPInputEnum.SCALAR_ANY,
        new DotMethodFPParam("an string-type calendar field name", EPLExpressionParamType.SPECIFIC, String.class),
        new DotMethodFPParam("a boolean-type up/down indicator", EPLExpressionParamType.SPECIFIC, boolean.class))
    };

  public DateTimeMethodDescriptor initialize(DateTimeMethodInitializeContext context) {
    return new DateTimeMethodDescriptor(FOOTPRINTS);
  }

  public DateTimeMethodOps validate(DateTimeMethodValidateContext context) {
    // this is an opportunity to do additional validation or evaluation when desired
    // however the footprint is already validated
    DateTimeMethodOpsModify roll = new DateTimeMethodOpsModify();
    
    // see below for MyLocalDTMRollUtility
    roll.setCalendarOp(new DateTimeMethodModeStaticMethod(MyLocalDTMRollUtility.class, "roll"));
    roll.setLdtOp(new DateTimeMethodModeStaticMethod(MyLocalDTMRollUtility.class, "roll"));
    roll.setZdtOp(new DateTimeMethodModeStaticMethod(MyLocalDTMRollUtility.class, "roll"));
    return roll;
 }
}</pre>
				<p>
					The following class handles the new <code class="literal">asArrayOfString</code> date-time method, which has single footprint that has a no parameters:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyLocalDTMForgeFactoryArrayOfString implements DateTimeMethodForgeFactory {
  private final static DotMethodFP[] FOOTPRINTS = new DotMethodFP[]{
    new DotMethodFP(DotMethodFPInputEnum.SCALAR_ANY)
  };

  public DateTimeMethodDescriptor initialize(DateTimeMethodInitializeContext context) {
    return new DateTimeMethodDescriptor(FOOTPRINTS);
  }

  public DateTimeMethodOps validate(DateTimeMethodValidateContext context) {
    DateTimeMethodOpsReformat asArrayOfString = new DateTimeMethodOpsReformat();
    asArrayOfString.setReturnType(String[].class);
    
    // see below for MyLocalDTMArrayOfStringUtility
    asArrayOfString.setLongOp(new DateTimeMethodModeStaticMethod(MyLocalDTMArrayOfStringUtility.class, "asArrayOfString"));
    asArrayOfString.setDateOp(new DateTimeMethodModeStaticMethod(MyLocalDTMArrayOfStringUtility.class, "asArrayOfString"));
    asArrayOfString.setCalendarOp(new DateTimeMethodModeStaticMethod(MyLocalDTMArrayOfStringUtility.class, "asArrayOfString"));
    asArrayOfString.setLdtOp(new DateTimeMethodModeStaticMethod(MyLocalDTMArrayOfStringUtility.class, "asArrayOfString"));
    asArrayOfString.setZdtOp(new DateTimeMethodModeStaticMethod(MyLocalDTMArrayOfStringUtility.class, "asArrayOfString"));
    return asArrayOfString;    
  }
}</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-datetimemethod-steptwo"></a>22.8.2. Implement the Static Methods</h3>
						</div>
					</div>
				</div>
				<p>
					For value-changing date-time methods that operate on <code class="literal">long</code>, <code class="literal">Date</code> and <code class="literal">Calendar</code>, the static method must return <code class="literal">void</code>, its first parameter must be <code class="literal">Calendar</code> and the remaining parameters much match the expression parameters, such as:
				</p>
				<pre class="synopsis">public static void roll(Calendar calendar, String fieldName, boolean flagValue) {</pre>
				<p>
					For value-changing date-time methods that operate on <code class="literal">LocalDateTime</code>, the static method must return <code class="literal">LocalDateTime</code>, its first parameter must be <code class="literal">LocalDateTime</code> and the remaining parameters much match the expression parameters, such as:
				</p>
				<pre class="synopsis">public static LocalDateTime roll(LocalDateTime ldt, String fieldName, boolean flagValue) {</pre>
				<p>
					For value-changing date-time methods that operate on <code class="literal">ZonedDateTime</code>, the static method must return <code class="literal">ZonedDateTime</code>, its first parameter must be <code class="literal">ZonedDateTime</code> and the remaining parameters much match the expression parameters, such as:
				</p>
				<pre class="synopsis">public static ZonedDateTime roll(ZonedDateTime zdt, String fieldName, boolean flagValue) {</pre>
				<p>
					For reformatting date-time methods, the static method must return the same type as provided by the <code class="literal">getReturnType</code> method of <code class="literal">DateTimeMethodReformatMode</code>, its first parameter must be any of the below and the remaining parameters much match the expression parameters (see example below).
				</p>
				<div class="itemizedlist">
					<ul>
						<li>
							<p>
								<code class="literal">long</code>
							</p>
						</li>
						<li>
							<p>
								<code class="literal">Date</code> (from java.util)
							</p>
						</li>
						<li>
							<p>
								<code class="literal">Calendar</code>
							</p>
						</li>
						<li>
							<p>
								<code class="literal">LocalDateTime</code>
							</p>
						</li>
						<li>
							<p>
								<code class="literal">ZonedDateTime</code>
							</p>
						</li>
					</ul>
				</div>
				<p>
					The class providing the static methods for the <code class="literal">roll</code> date-time method is shown next.
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyLocalDTMRollUtility {
  public static void roll(Calendar calendar, String fieldName, boolean flagValue) {
    switch (fieldName) {
      case "date": calendar.roll(Calendar.DATE, flagValue); break;
        default: throw new EPException("Invalid field name '" + fieldName + "'");
    }
  }

  public static LocalDateTime roll(LocalDateTime ldt, String fieldName, boolean flagValue) {
    switch (fieldName) {
      case "date": return ldt.plusDays(1);
        default: throw new EPException("Invalid field name '" + fieldName + "'");
    }
  }

  public static ZonedDateTime roll(ZonedDateTime zdt, String fieldName, boolean flagValue) {
    switch (fieldName) {
      case "date": return zdt.plusDays(1);
        default: throw new EPException("Invalid field name '" + fieldName + "'");
    }
  }
}</pre>
				<p>
					The class providing the static methods for the <code class="literal">asArrayOfString</code> date-time method is shown next.
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyLocalDTMArrayOfStringUtility {
  public static String[] asArrayOfString(long date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(date);
    return asArrayOfString(calendar);
  }

  public static String[] asArrayOfString(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    return asArrayOfString(calendar);
  }

  public static String[] asArrayOfString(Calendar calendar) {
    return new String[] {Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)),
      Integer.toString(calendar.get(Calendar.MONTH) + 1),
      Integer.toString(calendar.get(Calendar.YEAR))};
  }

  public static String[] asArrayOfString(LocalDateTime ldt) {
    return new String[] {Integer.toString(ldt.getDayOfMonth()),
      Integer.toString(ldt.getMonthValue()),
      Integer.toString(ldt.getYear())};
  }

  public static String[] asArrayOfString(ZonedDateTime zdt) {
    return new String[] {Integer.toString(zdt.getDayOfMonth()),
      Integer.toString(zdt.getMonthValue()),
      Integer.toString(zdt.getYear())};
    }
  }
}</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-datetimemethod-stepthree"></a>22.8.3. Add the Date-Time Method Extension to the Compiler Configuration</h3>
						</div>
					</div>
				</div>
				<p>You must provide the date-time method name and the forge factory class name to the compiler configuration.</p>
				<p>The sample XML snippet below configures the two example date-time methods:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-method-datetime method-name="roll" forge-class="packagename.MyLocalDTMForgeFactoryRoll"/&gt;
    &lt;plugin-method-datetime method-name="asArrayOfString" forge-class="packagename.MyLocalDTMForgeFactoryArrayOfString"/&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
				<p>The next example uses the configuration API to register the same:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">Configuration configuration = new Configuration();
configuration.getCompiler().addPlugInDateTimeMethod("roll", MyLocalDTMForgeFactoryRoll.class.getName());
configuration.getCompiler().addPlugInDateTimeMethod("asArrayOfString", MyLocalDTMForgeFactoryArrayOfString.class.getName());</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-datetimemethod-stepfour"></a>22.8.4. Use the new Date-Time Methods</h3>
						</div>
					</div>
				</div>
				<p>The sample EPL below uses the new methods:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select caldate.roll('date', true) as calroll,
  longdate.roll('date', true) as longroll,
  utildate.roll('date', true) as utilroll,
  localdate.roll('date', true) as localdateroll,
  zoneddate.roll('date', true) as zoneddateroll,
  caldate.asArrayOfString() as arraystring_from_cal,
  longdate.asArrayOfString() as arraystring_from_long,
  utildate.asArrayOfString() as arraystring_from_util,
  localdate.asArrayOfString() as arraystring_from_local,
  zoneddate.asArrayOfString() as arraystring_from_zoned
 from MyDateTimeEvent</pre>
			</div>
		</div>
		<div class="sect1" lang="en-US">
			<div class="titlepage">
				<div>
					<div>
						<h2 class="title"><a id="custom-enummethod"></a>22.9. Enumeration Method</h2>
					</div>
				</div>
			</div>
			<a id="d0e55712" class="indexterm"></a><a id="d0e55717" class="indexterm"></a>
			<p>Your application can provide additional enumeration methods by implementing the extension API as shown below. The steps are as follows:</p>
			<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
				<ol>
					<li>
						<p>
							Implement the <code class="literal">EnumMethodForgeFactory</code> interface (package <code class="literal">com.espertech.esper.common.client.hook.enummethod</code>) that the compiler invokes for validation and to receive information on the state class and the public static methods that your application exposes that provide the enumeration method logic.
						</p>
					</li>
					<li>
						<p>
							Implement the <code class="literal">EnumMethodState</code> that holds the state for enumerating over input values.
						</p>
					</li>
					<li>
						<p>Implement a static method (the processing method) that receives the state and each of the items of the collection of events, scalar values or object values and the result of lambda parameter expression evalutions.</p>
					</li>
					<li>
						<p>
							Add the class name of the <code class="literal">EnumMethodForgeFactory</code> implementation to the compiler configuration.
						</p>
					</li>
					<li>
						<p>Use the new enumeration method(s).</p>
					</li>
				</ol>
			</div>
			<p>
				The example herein builds a simple enumeration method by name <code class="literal">median</code> that computes the median for a set of integer-typed input values and that returns a double-type median.
			</p>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-enummethod-stepone"></a>22.9.1. Implement the <code class="literal">EnumMethodForgeFactory</code> Interface</h3>
						</div>
					</div>
				</div>
				<p>
					The implementation of the <code class="literal">EnumMethodForgeFactory</code> interface is responsible for:
				</p>
				<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
					<ol>
						<li>
							<p>
								The <code class="literal">initialize</code> method returns the available footprints.
							</p>
						</li>
						<li>
							<p>
								The <code class="literal">validate</code> method may validate actual provided parameters and returns an <code class="literal">EnumMethodModeStaticMethod</code> descriptor.
							</p>
						</li>
					</ol>
				</div>
				<p>
					The EPL compiler calls the <code class="literal">initialize</code> method to obtain the allowed footprints. It compares the footprints to the number and type of parameters actually provided.
				</p>
				<p>
					The example <code class="literal">median</code> enumeration method takes a scalar numeric values as input and has no parameters.
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">DotMethodFP[] footprints = new DotMethodFP[] {
    new DotMethodFP(DotMethodFPInputEnum.SCALAR_NUMERIC)
  };
return new EnumMethodDescriptor(footprints);</pre>
				<p>Additional examples for footprint are:</p>
				<div class="table">
					<a id="d0e55800"></a>
					<p class="title">
						<b>Table 22.2. Enumeration Method Footprint Examples</b>
					</p>
					<div class="table-contents">
						<table summary="Enumeration Method Footprint Examples" border="1">
							<colgroup>
								<col>
									<col>
							</colgroup>
							<thead>
								<tr>
									<th>Sample Footprint and Processing Method</th>
									<th>Comment</th>
								</tr>
							</thead>
							<tbody>
								<tr>
									<td><pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">new DotMethodFP(DotMethodFPInputEnum.EVENTCOLL, 
  new DotMethodFPParam(1, "predicate", EPLExpressionParamType.BOOLEAN))</pre> <pre class="synopsis">process(<span class="emphasis"><em>State_class</em></span> state, EventBean event, Boolean pass)</pre></td>
									<td>Enumeration method taking events as input and that has a single lambda expression that is a predicate and that returns a boolean value</td>
								</tr>
								<tr>
									<td><pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">new DotMethodFP(DotMethodFPInputEnum.SCALAR_ANY, 
  new DotMethodFPParam(1, "value-selector", EPLExpressionParamType.NUMERIC))
						      </pre> <pre class="synopsis">process(<span class="emphasis"><em>State_class</em></span> state, Object value, Object lambdaResult)</pre></td>
									<td>Enumeration method taking any type of scalar values as input and that has a single lambda expression that is a value-selector and that returns a numeric value</td>
								</tr>
								<tr>
									<td><pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">new DotMethodFP(DotMethodFPInputEnum.SCALAR_NUMERIC, 
  new DotMethodFPParam("from", EPLExpressionParamType.NUMERIC), 
  new DotMethodFPParam("to", EPLExpressionParamType.NUMERIC))</pre> <pre class="synopsis">process(<span class="emphasis"><em>State_class</em></span> state, Object value)</pre></td>
									<td>Enumeration method taking any type of numeric scalar values as input and that has no lambda expressions as parameter but two non-lambda expressions as parameter both returning a numeric value</td>
								</tr>
								<tr>
									<td><pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">new DotMethodFP(DotMethodFPInputEnum.EVENTCOLL, 
  new DotMethodFPParam(1, "v1", EPLExpressionParamType.ANY), 
  new DotMethodFPParam(1, "v2", EPLExpressionParamType.ANY))</pre> <pre class="synopsis">process(<span class="emphasis"><em>State_class</em></span> state, EventBean event, Object v1, Object v2)</pre></td>
									<td>Enumeration method taking events as input and that has two lambda expressions as parameter both returning any object value</td>
								</tr>
								<tr>
									<td><pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">new DotMethodFP(DotMethodFPInputEnum.ANY, 
  new DotMethodFPParam(2, "value, index", EPLExpressionParamType.BOOLEAN))</pre> <pre class="synopsis">process(<span class="emphasis"><em>State_class</em></span> state, EventBean event, Boolean pass)</pre></td>
									<td>Enumeration method taking any type of scalar values as input and that a single lambda expression that has 2 parameters (value and index, similar to <code class="literal">takeWhile</code> with index) and that returns a boolean value
									</td>
								</tr>
							</tbody>
						</table>
					</div>
				</div>
				<br class="table-break">
					<p>
						Use the <code class="literal">EnumMethodModeStaticMethod</code> class to provide the class of the state object and the class and the name of the public static method that is the processing method.
					</p>
					<p>
						The following class handles the new <code class="literal">median</code> enumeration method, which has single footprint that has no parameters:
					</p> <pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public static class MyLocalEnumMethodForgeMedian implements EnumMethodForgeFactory {
  private static final DotMethodFP[] FOOTPRINTS = new DotMethodFP[]{
    new DotMethodFP(DotMethodFPInputEnum.SCALAR_NUMERIC)
  };

  public EnumMethodDescriptor initialize(EnumMethodInitializeContext context) {
    return new EnumMethodDescriptor(FOOTPRINTS);
  }

  public EnumMethodModeStaticMethod validate(EnumMethodValidateContext context) {
    Class stateClass = MyLocalEnumMethodMedianState.class; // the class providing state, must implement EnumMethodState
    Class serviceClass = MyLocalEnumMethodMedianService.class; // the class providing the processing method (any class)
    String methodName = "next"; // the name of the method for processing an item of input values (any method name)
    EPChainableType returnType = EPChainableTypeHelper.singleValue(Double.class); // indicate that we are returning a Double-type value
    boolean earlyExit = false;
    return new EnumMethodModeStaticMethod(stateClass, serviceClass, methodName, returnType, earlyExit);
  }
}</pre>
					<p>
						The <code class="literal">EnumMethodModeStaticMethod</code> provides multiple settings to the EPL compiler:
					</p>
					<div class="itemizedlist">
						<ul>
							<li>
								<p>
									The class that implements the <code class="literal">EnumMethodState</code> interface which holds enumeration state.
								</p>
							</li>
							<li>
								<p>The class and method name of the method that processes values and that receives the result of lambda parameter evaluation.</p>
							</li>
							<li>
								<p>
									The return type of the enumeration method which is an <code class="literal">EPChainableType</code> value.
								</p>
							</li>
							<li>
								<p>An indicator whether the state requires early-access checking.</p>
							</li>
						</ul>
					</div>
					<p>
						The <code class="literal">EPChainableType</code> return type has the following choices:
					</p>
					<div class="itemizedlist">
						<ul>
							<li>
								<p>
									For a method returning a collection of events, always use <code class="literal">EPChainableTypeHelper.collectionOfEvents(context.getInputEventType())</code>.
								</p>
							</li>
							<li>
								<p>
									For a method returning a collection of objects, use <code class="literal">EPChainableTypeHelper.collectionOfSingleValue(<span class="emphasis"><em>class_of_value</em></span>)
									</code>.
								</p>
							</li>
							<li>
								<p>
									For a method returning a single scalar value, use <code class="literal">EPChainableTypeHelper.singleValue(<span class="emphasis"><em>class_of_value</em></span>)
									</code>.
								</p>
							</li>
						</ul>
					</div>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-enummethod-steptwo"></a>22.9.2. Implement the <code class="literal">EnumMethodState</code> Interface</h3>
						</div>
					</div>
				</div>
				<p>
					The implementation of the <code class="literal">EnumMethodState</code> interface is responsible for holding the transient state of one pass over input values to the enumeration method. The runtime allocates a new instance of the provided class for each execution of the enumeration method. The implementation class must have a default constructor.
				</p>
				<p>The state class does this:</p>
				<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
					<ol>
						<li>
							<p>
								The <code class="literal">state</code> method returns the final result.
							</p>
						</li>
						<li>
							<p>
								(Optional) Override the <code class="literal">setParameter</code> method to receive non-lambda expression parameter results.
							</p>
						</li>
						<li>
							<p>
								(Optional) Override the <code class="literal">completed</code> method to indicate early-exit.
							</p>
						</li>
					</ol>
				</div>
				<p>
					The following class handles the state for the <code class="literal">median</code> enumeration method and computes the median:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public class MyLocalEnumMethodMedianState implements EnumMethodState {
  private List&lt;Integer&gt; list = new ArrayList&lt;&gt;();

  public Object state() {
    Collections.sort(list);
    // get count of scores
    int totalElements = list.size();
    if (totalElements &lt; 2) {
      return null;
    }
    // check if total number of scores is even
    if (totalElements % 2 == 0) {
      int sumOfMiddleElements = list.get(totalElements / 2) + list.get(totalElements / 2 - 1);
      // calculate average of middle elements
      return ((double) sumOfMiddleElements) / 2;
    }
  return (double) list.get(totalElements / 2);
  }

  public void add(Integer value) {
    list.add(value);
  }
}</pre>
				<p>
					The example does not have additional non-lambda parameters and therefore does not override <code class="literal">setParameter</code>. Your application can receive any non-lambda expression values by overriding <code class="literal">setParameter</code>.
				</p>
				<p>
					The example does not have early-exit and therefore does not override <code class="literal">completed</code>. Your application can override <code class="literal">completed</code> to indicate an early exit. Please make sure <code class="literal">EnumMethodModeStaticMethod</code> has the early-exit flag set.
				</p>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-enummethod-stepthree"></a>22.9.3. Implement the Static Method for Processing</h3>
						</div>
					</div>
				</div>
				<p>The processing method is the method that the runtime invokes for each input element. There is no interface for the class providing the method and the method must be public and static.</p>
				<p>
					The processing method, that your application specified as part of <code class="literal">EnumMethodModeStaticMethod</code>, receives these values:
				</p>
				<div xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="orderedlist">
					<ol>
						<li>
							<p>The first parameter is always the state class as provided in the previous step.</p>
						</li>
						<li>
							<p>
								The second parameter is always the item value of type <code class="literal">EventBean</code> when the input is events, or type <code class="literal">Object</code> when the input is not events.
							</p>
						</li>
						<li>
							<p>The remaining parameters are the result of the runtime evaluating the expression bodies of lambda expression parameters to the enumeration method.</p>
						</li>
					</ol>
				</div>
				<p>
					The example <code class="literal">median</code> enumeration method takes scalar values as input and has no lambda expression parameters:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">public static class MyLocalEnumMethodMedianService {
  public static void next(MyLocalEnumMethodMedianState state, Object element) {
    state.add((Integer) element);
  }
}</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-enummethod-stepfour"></a>22.9.4. Add the Enumeration Method Extension to the Compiler Configuration</h3>
						</div>
					</div>
				</div>
				<p>You must provide the enumeration method name and the forge factory class name to the compiler configuration.</p>
				<p>The sample XML snippet below configures the two example date-time methods:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">&lt;esper-configuration xmlns="http://www.espertech.com/schema/esper"&gt;
  &lt;compiler&gt;
    &lt;plugin-method-enum method-name="median" forge-class="packagename.MyLocalEnumMethodForgeMedian"/&gt;
  &lt;/compiler&gt;
&lt;/esper-configuration&gt;</pre>
				<p>The next example uses the configuration API to register the same:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">Configuration configuration = new Configuration();
configuration.getCompiler().addPlugInEnumerationMethod("median", MyLocalEnumMethodForgeMedian.class.getName());</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-enummethod-stepfive"></a>22.9.5. Use the new Enumeration Method</h3>
						</div>
					</div>
				</div>
				<p>
					The sample EPL below uses the new method, assuming that the <code class="literal">MyIntegerValuesEvent</code> has an event property by name <code class="literal">intvalues</code> that returns an array or collection of int-type values:
				</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">select intvalues.median() as median from MyIntegerValuesEvent</pre>
			</div>
			<div class="sect2" lang="en-US">
				<div class="titlepage">
					<div>
						<div>
							<h3 class="title"><a id="custom-enummethod-lambda"></a>22.9.6. Further Information to Lambda Parameters</h3>
						</div>
					</div>
				</div>
				<p>There are three types of lambda parameters supported.</p>
				<p>
					When a lambda parameter is the value itself it is represented by <code class="literal">EnumMethodLambdaParameterTypeValue</code>. For example, in <code class="literal">orderItems.where(v =&gt; v.price &gt; 0)</code> the <code class="literal">v</code> parameter is the input item value itself, i.e. the event or scalar value depending on input. This is always the default and no additional code is required.
				</p>
				<p>
					When a lambda parameter is the index of the value it is represented by <code class="literal">EnumMethodLambdaParameterTypeIndex</code>. For example, in <code class="literal">orderItems.takeWhile( (v, ind) =&gt; ind &lt; 10)</code> the <code class="literal">ind</code> parameter is the numeric index of the item starting at zero.
				</p>
				<p>The below code snippet sets the lambda parameter types for value and index:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">mode.setLambdaParameters(descriptor -&gt; {
  if (descriptor.getLambdaParameterNumber() == 0) {
    return EnumMethodLambdaParameterTypeValue.INSTANCE;
  }
  return EnumMethodLambdaParameterTypeIndex.INSTANCE;
});</pre>
				<p>
					When a lambda parameter is provided by the state class itself it is represented by <code class="literal">EnumMethodLambdaParameterTypeStateGetter</code>. For example, in <code class="literal">orderItems.aggregate(0, (result, v) =&gt; result + v.price))</code> the <code class="literal">result</code> parameter is provided by the state itself.
				</p>
				<p>The below code snippet sets the lambda parameter types for state-provided and index:</p>
				<pre xmlns="" xmlns:d="http://docbook.org/ns/docbook" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="">mode.setLambdaParameters(descriptor -&gt; {
  if (descriptor.getLambdaParameterNumber() == 0) {
    // the state class has a getResult method returning string
    return new EnumMethodLambdaParameterTypeStateGetter(int.class, "getResult");
  }
  return EnumMethodLambdaParameterTypeValue.INSTANCE;
});</pre>
				<p>
					Note that the example above assumes that the state class has a <code class="literal">getResult</code> method returning an int-type value.
				</p>
				<p>For additional information and examples please consult the JavaDoc and regression testing code.</p>
			</div>
		</div>
	</div>
	<ul xmlns:d="http://docbook.org/ns/docbook" class="docnav">
		<li class="previous"><a accesskey="p" href="dataflow.html"><strong>Prev</strong>Chapter 21. EPL Reference: Data Flow</a></li>
		<li class="up"><a accesskey="u" href="#"><strong>Top of page</strong></a></li>
		<li class="home"><a accesskey="h" href="index.html"><strong>Front page</strong></a></li>
		<li class="next"><a accesskey="n" href="examples.html"><strong>Next</strong>Chapter 23. Examples, Tutorials, Case Studies</a></li>
	</ul>
</body>

</html>